From 3daea5c1d76815bb487d80136a8413718791054e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 09:43:56 +0100 Subject: [PATCH 01/60] Expand .gitignore --- .gitignore | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index f574456d..486320d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,39 @@ elm-stuff/ build/ -.metals/ -.vscode obj/ bin/ **/assets/js/main* **/assets/js/creator* **/assets/js/node_modules **/assets/css/ + +# JS +node_modules + +# sbt +target + +# mill +out + +# Scala-CLI +.scala-build + +# Direnv +.envrc +.direnv + +# Misc +.DS_Store + +# IDE's and other build tools +.idea +*.iml +.vscode +.vim +.metals +.bloop +metals.sbt +.bsp +.ammonite +.coursier From 5d45b1595b2c387aa2539142c45d074d7201e925 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 09:44:06 +0100 Subject: [PATCH 02/60] README typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 94b5c590..d37c64a8 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The quickest and easiest way to get up and running is by opening ### Using a Local Server If you'd rather use a local server than the online version (perhaps you're playing -ove LAN, or just fancy the technical challenge), then you can do that too! +over LAN, or just fancy the technical challenge), then you can do that too! In essence all you need to do is download the correct file and set up port forwarding, but more detailed instructions are below: From 6fd7efc3d30edbf46b59e33615e3125e8773e832 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 09:44:19 +0100 Subject: [PATCH 03/60] Basic Nix flake --- flake.lock | 42 ++++++++++++++++++++++++++++++++++++++++++ flake.nix | 21 +++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..36e9ea13 --- /dev/null +++ b/flake.lock @@ -0,0 +1,42 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1680776469, + "narHash": "sha256-3CXUDK/3q/kieWtdsYpDOBJw3Gw4Af6x+2EiSnIkNQw=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "411e8764155aa9354dbcd6d5faaeb97e9e3dce24", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1680939080, + "narHash": "sha256-llIGc5Gm9wIZRjShnmuFrsz/HV7cjdY3rkJ1q5Kah44=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "0d3d2a2231c762e59ac876b3920e569d5cf40646", + "type": "github" + }, + "original": { + "owner": "nixos", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..92053d10 --- /dev/null +++ b/flake.nix @@ -0,0 +1,21 @@ +{ + inputs.nixpkgs.url = "github:nixos/nixpkgs"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + + outputs = { nixpkgs, flake-utils, ... }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + jdkToUse = pkgs.jdk17; + sbtWithJRE = pkgs.sbt.override { jre = jdkToUse; }; + in + { + devShells.default = pkgs.mkShell { + packages = [ + jdkToUse + sbtWithJRE + ]; + }; + } + ); +} From 7d747be4d2809c7d1de28728bcecec40ae5d0c57 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 10:20:28 +0100 Subject: [PATCH 04/60] Initial Tyrian project set up --- .github/workflows/ci.yml | 15 + .gitignore | 4 + ci.sh | 15 + flake.nix | 2 +- ui/.mill-version | 1 + ui/.scalafix.conf | 26 + ui/.scalafmt.conf | 7 + ui/README.md | 25 + ui/build.sc | 46 + ui/index.html | 14 + ui/package.json | 9 + ui/tyrianapp.js | 3 + ui/ui/src/example/Main.scala | 30 + ui/ui/test/src/example/SiteTests.scala | 10 + ui/yarn.lock | 4532 ++++++++++++++++++++++++ 15 files changed, 4738 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml create mode 100644 ci.sh create mode 100644 ui/.mill-version create mode 100644 ui/.scalafix.conf create mode 100644 ui/.scalafmt.conf create mode 100644 ui/README.md create mode 100644 ui/build.sc create mode 100644 ui/index.html create mode 100644 ui/package.json create mode 100644 ui/tyrianapp.js create mode 100644 ui/ui/src/example/Main.scala create mode 100644 ui/ui/test/src/example/SiteTests.scala create mode 100644 ui/yarn.lock diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..c43dac7d --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,15 @@ +name: CI +on: [workflow_dispatch, push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: olafurpg/setup-scala@v11 + with: + java-version: adopt@1.19 + - uses: jodersky/setup-mill@master + with: + mill-version: 0.10.12 + - name: Compile & Test + run: bash ci.sh diff --git a/.gitignore b/.gitignore index 486320d5..22ac6405 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,7 @@ metals.sbt .bsp .ammonite .coursier + +# parcel +.parcel-cache +dist diff --git a/ci.sh b/ci.sh new file mode 100644 index 00000000..808cfddd --- /dev/null +++ b/ci.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -e + +cd ui + +mill clean ui +mill ui.compile +mill ui.checkFormat +mill ui.fix +mill ui.fastLinkJS +mill ui.test + +cd .. + diff --git a/flake.nix b/flake.nix index 92053d10..1bdfdc44 100644 --- a/flake.nix +++ b/flake.nix @@ -6,7 +6,7 @@ flake-utils.lib.eachDefaultSystem (system: let pkgs = import nixpkgs { inherit system; }; - jdkToUse = pkgs.jdk17; + jdkToUse = pkgs.jdk19; sbtWithJRE = pkgs.sbt.override { jre = jdkToUse; }; in { diff --git a/ui/.mill-version b/ui/.mill-version new file mode 100644 index 00000000..70016a7c --- /dev/null +++ b/ui/.mill-version @@ -0,0 +1 @@ +0.10.12 diff --git a/ui/.scalafix.conf b/ui/.scalafix.conf new file mode 100644 index 00000000..cfb1e1b8 --- /dev/null +++ b/ui/.scalafix.conf @@ -0,0 +1,26 @@ +rules = [ + DisableSyntax, + OrganizeImports +] + +OrganizeImports { + removeUnused = false +} + +DisableSyntax { + noVars = true + noThrows = true + noNulls = true + noReturns = true + noWhileLoops = true + noAsInstanceOf = false # Doesn't seem to work correctly + noIsInstanceOf = false # Doesn't seem to work correctly + noXml = true + noDefaultArgs = true + noFinalVal = true + noFinalize = true + noValPatterns = true + # noUniversalEquality = false # handled by scala 3 + # noUniversalEqualityMessage = "== and != are unsafe since they allow comparing two unrelated types" + # regex = [] +} diff --git a/ui/.scalafmt.conf b/ui/.scalafmt.conf new file mode 100644 index 00000000..7340ff78 --- /dev/null +++ b/ui/.scalafmt.conf @@ -0,0 +1,7 @@ +version = 3.3.0 +runner.dialect = scala3 +style = defaultWithAlign +maxColumn = 120 +rewrite.rules = [RedundantBraces,RedundantParens,PreferCurlyFors] +danglingParentheses.preset = true +lineEndings=preserve diff --git a/ui/README.md b/ui/README.md new file mode 100644 index 00000000..c54107cc --- /dev/null +++ b/ui/README.md @@ -0,0 +1,25 @@ +# Tyrian counter example built with Mill + +This is a minimal working project setup to run the counter example. + +The instructions on running below will do a compile of the mill project, but you can do it manually with: + +```sh +mill counter.buildSite +``` + +To run the program in a browser you will need to have yarn (or npm) installed. + +On first run: + +```sh +yarn install +``` + +and from then on + +```sh +yarn start +``` + +Then navigate to [http://localhost:1234/](http://localhost:1234/) diff --git a/ui/build.sc b/ui/build.sc new file mode 100644 index 00000000..cd2dcf6e --- /dev/null +++ b/ui/build.sc @@ -0,0 +1,46 @@ +import $ivy.`com.goyeau::mill-scalafix::0.2.11` +import com.goyeau.mill.scalafix.ScalafixModule +import $ivy.`com.lihaoyi::mill-contrib-bloop:$MILL_VERSION` +import mill._ +import mill.scalalib._ +import mill.scalajslib._ +import mill.scalajslib.api._ +import scalafmt._ + +import $ivy.`io.github.davidgregory084::mill-tpolecat::0.3.2` +import io.github.davidgregory084.TpolecatModule + +object ui extends ScalaJSModule with TpolecatModule with ScalafixModule with ScalafmtModule { + def scalaVersion = "3.2.2" + def scalaJSVersion = "1.13.0" + val tyrianVersion = "0.6.2" + + def buildSite() = + T.command { + T { + compile() + fastLinkJS() + } + } + + def ivyDeps = + Agg( + ivy"io.indigoengine::tyrian-io::$tyrianVersion" + ) + + override def moduleKind = T(mill.scalajslib.api.ModuleKind.CommonJSModule) + + def scalafixIvyDeps = Agg(ivy"com.github.liancheng::organize-imports:0.6.0") + + object test extends Tests { + def ivyDeps = Agg( + ivy"org.scalameta::munit::0.7.29" + ) + + def testFramework = "munit.Framework" + + override def moduleKind = T(mill.scalajslib.api.ModuleKind.CommonJSModule) + + } + +} diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 00000000..b4a676cf --- /dev/null +++ b/ui/index.html @@ -0,0 +1,14 @@ + + + + + + Tyrian Counter Example (Mill) + + + +
+ + + + diff --git a/ui/package.json b/ui/package.json new file mode 100644 index 00000000..cab14794 --- /dev/null +++ b/ui/package.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "start": "mill ui.buildSite && parcel index.html --no-cache --dist-dir dist --log-level info", + "build": "mill clean ui && mill ui.buildSite && parcel build index.html --dist-dir dist --log-level info" + }, + "devDependencies": { + "parcel": "^2.1.0" + } +} diff --git a/ui/tyrianapp.js b/ui/tyrianapp.js new file mode 100644 index 00000000..a1819174 --- /dev/null +++ b/ui/tyrianapp.js @@ -0,0 +1,3 @@ +import {TyrianApp} from './out/ui/fastLinkJS.dest/main.js'; + +TyrianApp.launch("myapp"); diff --git a/ui/ui/src/example/Main.scala b/ui/ui/src/example/Main.scala new file mode 100644 index 00000000..a3aecfcb --- /dev/null +++ b/ui/ui/src/example/Main.scala @@ -0,0 +1,30 @@ +import cats.effect.IO +import tyrian.Html.* +import tyrian.* + +import scala.scalajs.js.annotation.* + +@JSExportTopLevel("TyrianApp") +object Main extends TyrianApp[Msg, Model]: + + def init(flags: Map[String, String]): (Model, Cmd[IO, Msg]) = + (0, Cmd.None) + + def update(model: Model): Msg => (Model, Cmd[IO, Msg]) = + case Msg.Increment => (model + 1, Cmd.None) + case Msg.Decrement => (model - 1, Cmd.None) + + def view(model: Model): Html[Msg] = + div()( + button(onClick(Msg.Decrement))(text("-")), + div()(text(model.toString)), + button(onClick(Msg.Increment))(text("+")) + ) + + def subscriptions(model: Model): Sub[IO, Msg] = + Sub.None + +type Model = Int + +enum Msg: + case Increment, Decrement diff --git a/ui/ui/test/src/example/SiteTests.scala b/ui/ui/test/src/example/SiteTests.scala new file mode 100644 index 00000000..29b654f4 --- /dev/null +++ b/ui/ui/test/src/example/SiteTests.scala @@ -0,0 +1,10 @@ + + +import cats.effect.IO +class SiteTests extends munit.FunSuite { + + test("This test will pass") { + assert(1 == 1) + } + +} diff --git a/ui/yarn.lock b/ui/yarn.lock new file mode 100644 index 00000000..bbe34b95 --- /dev/null +++ b/ui/yarn.lock @@ -0,0 +1,4532 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.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/compat-data@^7.16.4": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== + +"@babel/core@^7.12.0": + 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" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.7.tgz#b42bf46a3079fa65e1544135f32e7958f048adbb" + integrity sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg== + dependencies: + "@babel/types" "^7.16.7" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/generator@^7.16.8", "@babel/generator@^7.9.0": + 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.16.8" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.8.4": + 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/compat-data" "^7.16.4" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + +"@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-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-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-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-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-plugin-utils@^7.16.7": + 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-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-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-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-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/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/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/parser@^7.0.0", "@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/parser@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e" + integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA== + +"@babel/plugin-syntax-flow@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz#202b147e5892b8452bbb0bb269c7ed2539ab8832" + integrity sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-flow-strip-types@^7.0.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.16.7.tgz#291fb140c78dabbf87f2427e7c7c332b126964b8" + integrity sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-flow" "^7.16.7" + +"@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/traverse@^7.0.0": + 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/traverse@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.7.tgz#dac01236a72c2560073658dd1a285fe4e0865d76" + integrity sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@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.7" + "@babel/types" "^7.16.7" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.12.13", "@babel/types@^7.16.8": + 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.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159" + integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@iarna/toml@^2.2.0": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" + integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== + +"@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" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@parcel/babel-ast-utils@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/babel-ast-utils/-/babel-ast-utils-2.2.0.tgz#8e1ab1f0118c1477ea50dd404d23d861502f7547" + integrity sha512-rIvqRJZ3ocPk9lZMQMlTgau3CO2bCI4fJb7lwiXVwK7E5XkJWcxyB3hplNXkSBCMDd69sQ9PNdZFW6wwzONuNQ== + dependencies: + "@babel/parser" "^7.0.0" + "@parcel/babylon-walk" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/utils" "^2.2.0" + astring "^1.6.2" + +"@parcel/babylon-walk@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/babylon-walk/-/babylon-walk-2.2.0.tgz#822ba7c74272d605a1edef24e7f57492373a2674" + integrity sha512-7H32Ln6hUAMaW46ba1S44l5EZ8l+boqQrV3iOVZEyPUUToOmFUD/TER+51M2CioXShvxdSZLVITKvbZLWRbTig== + dependencies: + "@babel/types" "^7.12.13" + lodash.clone "^4.5.0" + +"@parcel/bundler-default@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.2.0.tgz#85d5e8ae79641a9d9043ffdc2948ea4919dcf8b7" + integrity sha512-h661kIWbjcym8fh/cpTOosROCAMF/NgGdtQlQggxg9JKzH1Gj2ukxPk2uaJAML7k1MvKOF9B8PN1BRIGY3mxXA== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/hash" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + nullthrows "^1.1.1" + +"@parcel/cache@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.2.0.tgz#a3a12b6630e609b22b42b19a0a232656e50f1559" + integrity sha512-vzIuiui+VCIdvttIKIYen+IVNn6JbPv3I6MbJoNGM+UycVeK9N0yNAhSUbtZzGiBeyt1fLhq+46DSs11gV5IfA== + dependencies: + "@parcel/fs" "^2.2.0" + "@parcel/logger" "^2.2.0" + "@parcel/utils" "^2.2.0" + lmdb "^2.0.2" + +"@parcel/codeframe@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.2.0.tgz#76c6f7c617e7cef692d72950129e0d59a66d9ab6" + integrity sha512-mszI8sRyDvzqcixb82dCXZKGrt/uQu2VVDsjGp9Tra1ZDJcHqWAw4ikcXVrzPnYqV6QxbD/MPt3q8ktgLKZv+A== + dependencies: + chalk "^4.1.0" + emphasize "^4.2.0" + slice-ansi "^4.0.0" + string-width "^4.2.0" + +"@parcel/compressor-raw@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.2.0.tgz#6b93a4697b62eebe1ab7d0622a5651f220e1391b" + integrity sha512-w/SpIKuhlABjWQtWi6NyyHmgDMvEHsjvvGa9OhEycODz67KKEohkQ/YT5TmjBVBuljfY5XAocVKIKNuONV0DYA== + dependencies: + "@parcel/plugin" "^2.2.0" + +"@parcel/config-default@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.2.0.tgz#fef389dcfd49985de9901fd792a231970a240997" + integrity sha512-Xj4WaYpKxqAf5PEHMdRfOJSjFFslISQjPwRhoXTjHTCgzDHu/js+IsQ3iK1BDLsgq1g0KyLUVbP4xjzjfW/ANw== + dependencies: + "@parcel/bundler-default" "^2.2.0" + "@parcel/compressor-raw" "^2.2.0" + "@parcel/namer-default" "^2.2.0" + "@parcel/optimizer-cssnano" "^2.2.0" + "@parcel/optimizer-htmlnano" "^2.2.0" + "@parcel/optimizer-image" "^2.2.0" + "@parcel/optimizer-svgo" "^2.2.0" + "@parcel/optimizer-terser" "^2.2.0" + "@parcel/packager-css" "^2.2.0" + "@parcel/packager-html" "^2.2.0" + "@parcel/packager-js" "^2.2.0" + "@parcel/packager-raw" "^2.2.0" + "@parcel/packager-svg" "^2.2.0" + "@parcel/reporter-dev-server" "^2.2.0" + "@parcel/resolver-default" "^2.2.0" + "@parcel/runtime-browser-hmr" "^2.2.0" + "@parcel/runtime-js" "^2.2.0" + "@parcel/runtime-react-refresh" "^2.2.0" + "@parcel/runtime-service-worker" "^2.2.0" + "@parcel/transformer-babel" "^2.2.0" + "@parcel/transformer-css" "^2.2.0" + "@parcel/transformer-html" "^2.2.0" + "@parcel/transformer-image" "^2.2.0" + "@parcel/transformer-js" "^2.2.0" + "@parcel/transformer-json" "^2.2.0" + "@parcel/transformer-postcss" "^2.2.0" + "@parcel/transformer-posthtml" "^2.2.0" + "@parcel/transformer-raw" "^2.2.0" + "@parcel/transformer-react-refresh-wrap" "^2.2.0" + "@parcel/transformer-svg" "^2.2.0" + +"@parcel/core@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.2.0.tgz#0586b0bbc9dcda48720a62cad799a3b3464b24e7" + integrity sha512-5VvSEIHqfvTSk7aX1dcvyhZTkhSiJcma8SDpQ5wTCDhK0SScInl+y7yH2v8soUaRMDE3LD4uzYLaSoJeJH/BpQ== + dependencies: + "@parcel/cache" "^2.2.0" + "@parcel/diagnostic" "^2.2.0" + "@parcel/events" "^2.2.0" + "@parcel/fs" "^2.2.0" + "@parcel/graph" "^2.2.0" + "@parcel/hash" "^2.2.0" + "@parcel/logger" "^2.2.0" + "@parcel/package-manager" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/types" "^2.2.0" + "@parcel/utils" "^2.2.0" + "@parcel/workers" "^2.2.0" + abortcontroller-polyfill "^1.1.9" + base-x "^3.0.8" + browserslist "^4.6.6" + clone "^2.1.1" + dotenv "^7.0.0" + dotenv-expand "^5.1.0" + json-source-map "^0.6.1" + json5 "^1.0.1" + micromatch "^4.0.2" + msgpackr "^1.5.1" + nullthrows "^1.1.1" + semver "^5.7.1" + +"@parcel/diagnostic@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.2.0.tgz#717eba5d34da337c5ec0aa26cd2d2868da600edb" + integrity sha512-NJcuf7e3mbgcsaqaRq7XFLeYjAm4PJ+ZBNQGZhnnMgPDT4PjOAPUqBTBIjWyjbqRyxEosgSMbMxsZs6+U4Tt/g== + dependencies: + json-source-map "^0.6.1" + nullthrows "^1.1.1" + +"@parcel/events@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.2.0.tgz#a599aa4237b90672b01f6886934e88d8e1fd4b13" + integrity sha512-d5H9jPnCjVuNErNcDVFwxHK5zEUNr4wTcSH0CIeLshq/Z5mGhDlLC42QN4PuTR+9vHc56LlmEVrEKsLcTY5v8g== + +"@parcel/fs-search@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.2.0.tgz#de2be8829bb86db650594a1e4f37167afcac7334" + integrity sha512-EsyNFKGgixxGHTNEmfY3xGMEpAAFwEquHbaYn76SlXfQ6CLHjfGLPU5DkodSbiYE2uGwGbDQdChF60kYrHhIeQ== + dependencies: + detect-libc "^1.0.3" + +"@parcel/fs-write-stream-atomic@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/fs-write-stream-atomic/-/fs-write-stream-atomic-2.2.0.tgz#1b73f52151973b064208d7db35f8ffec6ccb2a11" + integrity sha512-c3nJJrsmxaFq0qDyRybq1f6hA7pD/gBj5N3FfFUbabMhKcPf/1tA9me4je4qiErtFPU25RmcL2X36mCrF9SvIg== + dependencies: + graceful-fs "^4.1.2" + iferr "^1.0.2" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +"@parcel/fs@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.2.0.tgz#1c9b13025b24f1c117bd712eab80717b7d4ff045" + integrity sha512-dn0TZAH98OYaSQwk5JrpfNmoPXn8tH5lbHKKm8VP8a1RhrG5TdynYbeZ8uu5XQ2FK1+M66/HtAdFLBLlevlWrw== + dependencies: + "@parcel/fs-search" "^2.2.0" + "@parcel/fs-write-stream-atomic" "^2.2.0" + "@parcel/types" "^2.2.0" + "@parcel/utils" "^2.2.0" + "@parcel/watcher" "^2.0.0" + "@parcel/workers" "^2.2.0" + graceful-fs "^4.2.4" + mkdirp "^0.5.1" + ncp "^2.0.0" + nullthrows "^1.1.1" + rimraf "^3.0.2" + utility-types "^3.10.0" + +"@parcel/graph@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.2.0.tgz#8a13b9e8c17c0074f9acbdffdf9f45ce37a14a47" + integrity sha512-3c1AZWO7ndpHPBxK1R+z+jS2MBBlsu2bKWVfUAPU3I9tGCGXKOhH5i/gO/jURSHx3g5s6ygZbfljAodpZ7W2DQ== + dependencies: + "@parcel/utils" "^2.2.0" + nullthrows "^1.1.1" + +"@parcel/hash@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.2.0.tgz#12eb373a7fe64c791822a0655bd661e632e45e06" + integrity sha512-lXN4dY3y5ZxUP52jhd+C99kSWJRjIbh0lMpMqMGhkdIRoJUpvv24kQ2aItcgqazWWR9SS1NDZ0/z7+vHPMmEFw== + dependencies: + detect-libc "^1.0.3" + xxhash-wasm "^0.4.2" + +"@parcel/logger@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.2.0.tgz#ceb6783cc9fa807837f8a1b6a17856746c511753" + integrity sha512-HEiPq7EVmttDVZocebNbHDDhTWDUVD8UizLkRrLCtdRQGTcK0+WFitooamhjCQKXG0T/4/dh8ojIfWTQPMCFLg== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/events" "^2.2.0" + +"@parcel/markdown-ansi@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.2.0.tgz#507c2cd533a09ac27bb799d2905962c67c7b2861" + integrity sha512-N46Yun+jRA97rEhOKyMC3awIULw6KRPsV2JkI9yfc5EiOOA1CYmVNIB6OmgmuuvZYwq9OoHxB+XFkXF+yxiWBA== + dependencies: + chalk "^4.1.0" + +"@parcel/namer-default@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.2.0.tgz#51bee03db280b671677b2324bac118bab4c3369e" + integrity sha512-Iz5MLGTTLd5zQ+CbyV/4VjOiTFaQJaMwwu3W/GfaI2eLou2d9bazFaa786b4UM9u0LjLKYaUUzWDohllSwBwSg== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/plugin" "^2.2.0" + nullthrows "^1.1.1" + +"@parcel/node-libs-browser@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/node-libs-browser/-/node-libs-browser-2.2.0.tgz#bf5feabe76378f6504a4a72250a9438ec4892792" + integrity sha512-RtaJG+cdo60+ffq+tD9OwtTAqRG4cAyrFxWbeqYPb+RenpZJBWBJHRy1C5cjtH98sfXPzwMzROayQviFBvRq5w== + dependencies: + assert "^2.0.0" + browserify-zlib "^0.2.0" + buffer "^5.5.0" + console-browserify "^1.2.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.12.0" + domain-browser "^3.5.0" + events "^3.1.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "^1.0.0" + process "^0.11.10" + punycode "^1.4.1" + querystring-es3 "^0.2.1" + stream-browserify "^3.0.0" + stream-http "^3.1.0" + string_decoder "^1.3.0" + timers-browserify "^2.0.11" + tty-browserify "^0.0.1" + url "^0.11.0" + util "^0.12.3" + vm-browserify "^1.1.2" + +"@parcel/node-resolver-core@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.2.0.tgz#8aca3e8904a628e77d62bb0a8d310d0dcfc8960f" + integrity sha512-/YssRfsNLMQAYuNAGMOqThTbiWHQLJbDxsT7V/L387UkinR7TZl0ZKNjAwmb+DMD2oTKZfgLcUnLCcEyg9numg== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/node-libs-browser" "^2.2.0" + "@parcel/utils" "^2.2.0" + micromatch "^4.0.4" + nullthrows "^1.1.1" + +"@parcel/optimizer-cssnano@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-cssnano/-/optimizer-cssnano-2.2.0.tgz#7df8d0f2b85ea088c4154167b71680cc0ab678c9" + integrity sha512-YpVFJO9v8TqGZVvonu5OOmUS7AOn1z9t+YaqiuD/ytJGyePVPIBoZ9H6TlL17jLv0gbAXTTv1zoLDmae4/ruZQ== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/source-map" "^2.0.0" + cssnano "^5.0.5" + postcss "^8.3.0" + +"@parcel/optimizer-htmlnano@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.2.0.tgz#a12f77bbf9c4de6468d62f73cb8e1a108ede6c3c" + integrity sha512-Lrsjz5sG5uayhIGAcAv5IqOPY8FJnsy4XeT0EUc70cAI9p3NS48HZqqPfWAn9nsMqu3EBhKNyFpiaJ4LY6LNkg== + dependencies: + "@parcel/plugin" "^2.2.0" + htmlnano "^1.0.1" + nullthrows "^1.1.1" + posthtml "^0.16.5" + svgo "^2.4.0" + +"@parcel/optimizer-image@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.2.0.tgz#d8ebc71bff53cc5ccde5e5cc0e2d2523f5ff0b59" + integrity sha512-bvrR7wX4GbcqR38MzSVImedyL3huFeMxyjdpElq6J4RKIGY3KK/+k4VhVzU0wGqIx+XTuJxNJWJGkJ8i+mESEw== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + "@parcel/workers" "^2.2.0" + detect-libc "^1.0.3" + +"@parcel/optimizer-svgo@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.2.0.tgz#fa84d90c51571266c96c815494a5321f03df3208" + integrity sha512-gBMQPn4EGOGsEQI0MjK1PoD7w2QrMvoyk7QvSbES1F91lhYh4e3zc1op3G/hdT6IiudlrbNgsSvMZCuxyFp6Uw== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + svgo "^2.4.0" + +"@parcel/optimizer-terser@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.2.0.tgz#db672ca93c67326de64aa58aacde2c012ae71ba5" + integrity sha512-R0QC9JAFJpoPS4mUltVLHbiLOeyv5G5kmM2MhJN3VYJyJNForMHvFwFBRQLxp8GbJ9pU3P36dN8jRfrlPQffog== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/utils" "^2.2.0" + nullthrows "^1.1.1" + terser "^5.2.0" + +"@parcel/package-manager@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.2.0.tgz#8c37dd1cb5e508b33f2600a5228873d5837b2aa6" + integrity sha512-FTh8/E6AMvRJTbNav7MD8ZULvTuZhUKBpfQu07oL1khE4O6KYyQ8NBGk3W221dfY+vXoM2+b+4BrKBgw8Sn3EA== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/fs" "^2.2.0" + "@parcel/logger" "^2.2.0" + "@parcel/types" "^2.2.0" + "@parcel/utils" "^2.2.0" + "@parcel/workers" "^2.2.0" + command-exists "^1.2.6" + cross-spawn "^6.0.4" + nullthrows "^1.1.1" + semver "^5.7.1" + split2 "^3.1.1" + +"@parcel/packager-css@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.2.0.tgz#d2c13249f8ecaab571b4d301bb94f64ef065a6a6" + integrity sha512-FUn7HEDb3q6/T4Z0We+kpD5zKYwEkK2ClTyDAEDvnqtEz2A+DIrvxarwtW8NlA+uSKOH+kioMrV7Gdl0RpN5XA== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/utils" "^2.2.0" + nullthrows "^1.1.1" + postcss "^8.3.0" + +"@parcel/packager-html@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.2.0.tgz#af3e53d2270e82301c08831c1913595b0e629aef" + integrity sha512-Hbp7z/1TQb5WZcystsO6ICuUVJblkVaWMw60hVDezkLsKTB87Qc81OIsqyST3LMhqM7NipsNqpaXvmg3wF6zrA== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/types" "^2.2.0" + "@parcel/utils" "^2.2.0" + nullthrows "^1.1.1" + posthtml "^0.16.5" + +"@parcel/packager-js@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.2.0.tgz#f0347dd240d77c42bc9f007f26bb174144d9eacc" + integrity sha512-dQmJqRAjy0RxWqGDSkfpyxMcUx3btqltSdK/Z8sUPVvNfss1gHRuz3Ee5CJxNoLLN8On+qM4xAvq2W3y16psbA== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/hash" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/utils" "^2.2.0" + globals "^13.2.0" + nullthrows "^1.1.1" + +"@parcel/packager-raw@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.2.0.tgz#83de58ed88830d49066a6141497d035a201c0f19" + integrity sha512-Iz/rltpChammeEUotDZqzZr5WZcJGr2ro68GBt/8/oMU0HDWItsWUF8EtsqSuPiQWYU+65xcXPguk2cQ1qXObg== + dependencies: + "@parcel/plugin" "^2.2.0" + +"@parcel/packager-svg@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.2.0.tgz#7e86a83b385c2d3134444d499f344a6a13f06570" + integrity sha512-APNuRVV6fRg36rL+H4nORCOe/gxzkDjF8UUldQLbxZdsYaL+9YvJA+4vmULce96b9Fcq7ZOkqUeDvQmWw9kLNw== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/types" "^2.2.0" + "@parcel/utils" "^2.2.0" + posthtml "^0.16.4" + +"@parcel/plugin@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.2.0.tgz#dfd80fd5c8e9663b2a08b1235297ab7abdadcca4" + integrity sha512-etIxpizU14aZELSV/qEeuufoC5fLgopQ9I0j/Y9ExSmlU3NH79NeQo0JPP1TU49ZOL8Si9o/D6tlhojle6GbzA== + dependencies: + "@parcel/types" "^2.2.0" + +"@parcel/reporter-cli@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.2.0.tgz#2f220cc2d5bf02674dd1b1c546794b34785422e5" + integrity sha512-FVRnSu5Yba/18X3KWiJEXLfT8KugsNoQmvnfL7FDgVbdxUS/RWPeAwICfXPH9pkqZBl9c7QcMDVtnSD3xNR8FA== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/types" "^2.2.0" + "@parcel/utils" "^2.2.0" + chalk "^4.1.0" + filesize "^6.1.0" + nullthrows "^1.1.1" + ora "^5.2.0" + string-width "^4.2.0" + strip-ansi "^6.0.0" + term-size "^2.2.1" + wrap-ansi "^7.0.0" + +"@parcel/reporter-dev-server@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.2.0.tgz#307d386197f45bd2c7b8e25c5c25142d89400b87" + integrity sha512-r6FRJ1BU/zHZvAxSvG5p0o2ZJgEkYDqU2y99a5tvRhQAIMupNp9Oc3PkAIOcoGtM3aiJvGO5pwDBoOpNwS4hwQ== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + connect "^3.7.0" + ejs "^3.1.6" + http-proxy-middleware "^1.0.0" + nullthrows "^1.1.1" + serve-handler "^6.0.0" + ws "^7.0.0" + +"@parcel/resolver-default@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.2.0.tgz#8e45d483e26e6df0698f9c1d93d1d7535f38df5c" + integrity sha512-mDEmFVcNI4AAnKZ2P44AqKGVpG2vt9npmRNRyCw1QZvCnETiTVvHl0AngVtZRP6DVw0MeuPt7JaFWy3DQ+LMnQ== + dependencies: + "@parcel/node-resolver-core" "^2.2.0" + "@parcel/plugin" "^2.2.0" + +"@parcel/runtime-browser-hmr@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.2.0.tgz#458f77b46190de6835457bf3cf5dc1ae554a6dcb" + integrity sha512-Y3K8bpm06xZ2IgzS8l8iBhHoc04CcJzwWsRS60xGHikDxkZWbUMCvxMjgUS6NmDo62aY3dFkD6VVFKZIRnWxCQ== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + +"@parcel/runtime-js@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.2.0.tgz#a0ba9345390398c372e3fe2fea944916ad554b62" + integrity sha512-XgI/lmX/7Lp9y9KpnxehryvbHtKs9KVLs6V6MmiMXb7s74S/A6cj4cWq+AhSfz2mZtvMJAhIw3bl5vYNx8qEog== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + nullthrows "^1.1.1" + +"@parcel/runtime-react-refresh@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.2.0.tgz#1f4a56a83aa90df1432628560309f1c93c663449" + integrity sha512-bnIW3K37cH2PoGXl5NX8401exe97VGORz5YTAm6BSHiXKWZkOHwE6dTj6/PydQRm4NLAiYlJ6hvxcu5QkF7/jw== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + react-refresh "^0.9.0" + +"@parcel/runtime-service-worker@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.2.0.tgz#630f97b8b136287b9825e09242bf1c02331da96d" + integrity sha512-+lwIBdTbhvhkYYNKG5ZxMaQ2wY/eaJqDjVelEpfvuoRzjR+v2YwKyAP4wV8DKzMb/lbtj6fsG+GerqaSwGVdDg== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + nullthrows "^1.1.1" + +"@parcel/source-map@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.0.0.tgz#41cf004109bbf277ceaf096a58838ff6a59af774" + integrity sha512-njoUJpj2646NebfHp5zKJeYD1KwhsfQIoU9TnCTHmF9fGOaPbClmeq12G6/4ZqGASftRq+YhhukFBi/ncWKGvw== + dependencies: + detect-libc "^1.0.3" + globby "^11.0.3" + +"@parcel/transformer-babel@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.2.0.tgz#0dda0da9f6f9df59d5e2dcc13085c96a84b6985f" + integrity sha512-amZIncU9Ld/SuIWajntAOXwsgYl6h+5e2qBIPYuFhZX3FrbhHJFJQ27GJxOmRu+C09JOpAQk7vlr6Oi6jLvxNw== + dependencies: + "@babel/core" "^7.12.0" + "@babel/generator" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.4" + "@babel/plugin-transform-flow-strip-types" "^7.0.0" + "@babel/traverse" "^7.0.0" + "@parcel/babel-ast-utils" "^2.2.0" + "@parcel/diagnostic" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/utils" "^2.2.0" + browserslist "^4.6.6" + core-js "^3.2.1" + json5 "^2.1.0" + nullthrows "^1.1.1" + semver "^5.7.0" + +"@parcel/transformer-css@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.2.0.tgz#b06fd42112f375541bcaaa3565a99d7b1d5aefa1" + integrity sha512-90GNysl/E8ScT6VxAqkgmsOi5HxkzX5xuj8YjjyKGls2DO3wZKjIi8q5ZGKjKLcWfKdF5gCzuvuObcg9nyMLug== + dependencies: + "@parcel/hash" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/utils" "^2.2.0" + css-modules-loader-core "^1.1.0" + nullthrows "^1.1.1" + postcss "^8.3.0" + postcss-modules "^3.2.2" + postcss-value-parser "^4.1.0" + semver "^5.7.1" + +"@parcel/transformer-html@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.2.0.tgz#2149b6cad3e8d49cf331823abc6ea13b81f0501b" + integrity sha512-Swvo4TUqyGcwN3AsUMRg5dZRaJnS2DUapJlr7wHmf5bL8Q0GOuGDLLZpK5SOmQn9aZSJ6uoof5gu9zoca+s5Ig== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/hash" "^2.2.0" + "@parcel/plugin" "^2.2.0" + nullthrows "^1.1.1" + posthtml "^0.16.5" + posthtml-parser "^0.10.1" + posthtml-render "^3.0.0" + semver "^5.7.1" + +"@parcel/transformer-image@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.2.0.tgz#8348f426cadb3cae1d7a7adbca3a3d9bc9ef3d11" + integrity sha512-9MRmgNRi8Dg+GMA1378smh0m/xfzPpTljR23jKvwviNsz54Tf67pC328DGaI6+5eNIw4fYFZxJTXcOSAVVKk2Q== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/workers" "^2.2.0" + nullthrows "^1.1.1" + +"@parcel/transformer-js@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.2.0.tgz#06b2b323e6839d35e8e56395d99726fe052c82cb" + integrity sha512-sD9NXeO6j6wEe8zkRcVU235fLGhyBWEhOpAbqd23+YjFgwpYq58aqw0v2tX3Ifv+jFuw8wYvRbN7Eq4hCKdjSw== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/utils" "^2.2.0" + "@parcel/workers" "^2.2.0" + "@swc/helpers" "^0.2.11" + browserslist "^4.6.6" + detect-libc "^1.0.3" + micromatch "^4.0.2" + nullthrows "^1.1.1" + regenerator-runtime "^0.13.7" + semver "^5.7.1" + +"@parcel/transformer-json@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.2.0.tgz#f053c0c04e6b6b2b060c4ac28077dbbede8c2ccc" + integrity sha512-SukzfuncSeK0nFahA4cgSNM9JAltp1TZBiIFTi6sufAfpr4g8de04uk8l09dPxEggSkRGFGvxiNeJfxXGqEkMg== + dependencies: + "@parcel/plugin" "^2.2.0" + json5 "^2.1.0" + +"@parcel/transformer-postcss@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.2.0.tgz#0ddc5455f58dab1fe873307c02a86a334f164ea3" + integrity sha512-u8aZ63oL9N28HXZTQPVz3eYoza+BzI86qXqrpT5nsTEHypnRiskih25ucwkYjWyBrOUavIn+ihLO7qKaVgGixQ== + dependencies: + "@parcel/hash" "^2.2.0" + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + clone "^2.1.1" + css-modules-loader-core "^1.1.0" + nullthrows "^1.1.1" + postcss-modules "^3.2.2" + postcss-value-parser "^4.1.0" + semver "^5.7.1" + +"@parcel/transformer-posthtml@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.2.0.tgz#dc85d0e474df2a2cd3a5ed61cb241bc2edd59e64" + integrity sha512-7xtnLh2wrVLZiU0pTkUWNwr2S4v3u/lgDDSr6UNQcjDHMdMUdbN8CIoraYNm3cEiTzb8O6OQEYHyH2ZEc753Xw== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + nullthrows "^1.1.1" + posthtml "^0.16.5" + posthtml-parser "^0.10.1" + posthtml-render "^3.0.0" + semver "^5.7.1" + +"@parcel/transformer-raw@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.2.0.tgz#f5c623996b0e819bca87ede51d73de9bcc277a57" + integrity sha512-xSSulmsPFNi6T/Ji/GeWIe3UatHEAemIBX3KZsvDDjy0P4olaNmeU/IvL+bb1H4NXKynOAgzyIR0S7bEpIj6Fw== + dependencies: + "@parcel/plugin" "^2.2.0" + +"@parcel/transformer-react-refresh-wrap@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.2.0.tgz#f6c6040b9d1edaecd880e8c21f66211cf6ae19fb" + integrity sha512-bPFXG7nB3dleH1pAfvlPXOY02CR5DZCoAGmu+D24VUyXXIEOX6RlB6nGls10FL7FSMLT1Q2iuJCS4DsFMIXLsw== + dependencies: + "@parcel/plugin" "^2.2.0" + "@parcel/utils" "^2.2.0" + react-refresh "^0.9.0" + +"@parcel/transformer-svg@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.2.0.tgz#f38c8f2809afa162380af0fb98d26e695cb2119a" + integrity sha512-tiGRVgwm/Fc36H/JUkvzcHAs+BPfOVcb171bgu5zUkDhfFj6ty5fvAQ9OThHJ6mV1vv/KGJuPbH4N1+wW/P4zQ== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/hash" "^2.2.0" + "@parcel/plugin" "^2.2.0" + nullthrows "^1.1.1" + posthtml "^0.16.5" + posthtml-parser "^0.10.1" + posthtml-render "^3.0.0" + semver "^5.7.1" + +"@parcel/types@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.2.0.tgz#781cacacda6ccb02c4f0454463ec408a28f4f9bb" + integrity sha512-QmzC/EowXifXYCRwWZS1/jC5yiWCV1R5YuKDhEj9AgKU6LOAMXAnfBwYB4jRnY+1Zv+n/Pf2LD24sz02sXzScQ== + dependencies: + "@parcel/cache" "^2.2.0" + "@parcel/diagnostic" "^2.2.0" + "@parcel/fs" "^2.2.0" + "@parcel/package-manager" "^2.2.0" + "@parcel/source-map" "^2.0.0" + "@parcel/workers" "^2.2.0" + utility-types "^3.10.0" + +"@parcel/utils@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.2.0.tgz#92d88f4603f943d10208728369881c667b3b6fd6" + integrity sha512-H1SqGvbhlNIFoiMTLX/aEGCGG0KYWQCc9Nf5BJ+75/lTaznZKCcUgv4pqu5j2PxmKlyl61aNkX69H9lWjdcvMw== + dependencies: + "@iarna/toml" "^2.2.0" + "@parcel/codeframe" "^2.2.0" + "@parcel/diagnostic" "^2.2.0" + "@parcel/hash" "^2.2.0" + "@parcel/logger" "^2.2.0" + "@parcel/markdown-ansi" "^2.2.0" + "@parcel/source-map" "^2.0.0" + ansi-html-community "0.0.8" + chalk "^4.1.0" + clone "^2.1.1" + fast-glob "3.1.1" + fastest-levenshtein "^1.0.8" + is-glob "^4.0.0" + is-url "^1.2.2" + json5 "^1.0.1" + lru-cache "^6.0.0" + micromatch "^4.0.4" + node-forge "^1.2.1" + nullthrows "^1.1.1" + open "^7.0.3" + terminal-link "^2.1.1" + +"@parcel/watcher@^2.0.0": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.0.5.tgz#f913a54e1601b0aac972803829b0eece48de215b" + integrity sha512-x0hUbjv891omnkcHD7ZOhiyyUqUUR6MNjq89JhEI3BxppeKWAm6NPQsqqRrAkCJBogdT/o/My21sXtTI9rJIsw== + dependencies: + node-addon-api "^3.2.1" + node-gyp-build "^4.3.0" + +"@parcel/workers@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.2.0.tgz#12f9774c9dc3c4e6a8427e9c7b79ee59dc20f2b6" + integrity sha512-qJTC+61LMz5eBHvT0lT+auoTKDzh/FemQrWzCdcQZjgECQyLYdD6GtMeCZP745pDfXcYZpflbSGZChIUnt1yDg== + dependencies: + "@parcel/diagnostic" "^2.2.0" + "@parcel/logger" "^2.2.0" + "@parcel/types" "^2.2.0" + "@parcel/utils" "^2.2.0" + chrome-trace-event "^1.0.2" + nullthrows "^1.1.1" + +"@swc/helpers@^0.2.11": + version "0.2.14" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.2.14.tgz#20288c3627442339dd3d743c944f7043ee3590f0" + integrity sha512-wpCQMhf5p5GhNg2MmGKXzUNwxe7zRiCsmqYsamez2beP7mKPCSiu+BjZcdN95yYSzO857kr0VfQewmGpS77nqA== + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +"@types/http-proxy@^1.17.5": + 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/node@*": + version "17.0.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" + integrity sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg== + +"@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== + +abab@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +abortcontroller-polyfill@^1.1.9: + version "1.7.3" + resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz#1b5b487bd6436b5b764fd52a612509702c3144b5" + integrity sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q== + +acorn-globals@^4.3.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" + integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== + dependencies: + acorn "^6.0.1" + acorn-walk "^6.0.1" + +acorn-walk@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" + integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== + +acorn@^6.0.1, acorn@^6.0.4: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + +ajv@^6.12.3: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +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" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +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-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +asn1@~0.2.3: + 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" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32" + integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A== + dependencies: + es6-object-assign "^1.1.0" + is-nan "^1.2.1" + object-is "^1.0.1" + util "^0.12.0" + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +astring@^1.6.2: + version "1.8.1" + resolved "https://registry.yarnpkg.com/astring/-/astring-1.8.1.tgz#a91c4afd4af3523e11f31242a3d5d9af62bb6cc6" + integrity sha512-Aj3mbwVzj7Vve4I/v2JYOPFkCGM2YS7OqQTNSxmUR+LECRpokuPgAYghePgr6SALDo5bD5DlfbSaYjOzGJZOLQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@0.9.x: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.8: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.0.0, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.6.6: + 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.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + +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-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001286: + version "1.0.30001296" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001296.tgz#d99f0f3bee66544800b93d261c4be55a35f1cec8" + integrity sha512-WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colord@^2.9.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1" + integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +command-exists@^1.2.6: + version "1.2.9" + resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0, commander@^7.2.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@^8.0.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +console-browserify@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +core-js@^3.2.1: + version "3.20.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.20.3.tgz#c710d0a676e684522f3db4ee84e5e18a9d11d69a" + integrity sha512-vVl8j8ph6tRS3B8qir40H7yw7voy17xL0piAjlbBUsH7WIfzoedL/ZOr1OV9FyZQLWXsayOJyV4tnRyXR85/ag== + +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@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^6.0.4: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-declaration-sorter@^6.0.3: + version "6.1.4" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.4.tgz#b9bfb4ed9a41f8dcca9bf7184d849ea94a8294b4" + integrity sha512-lpfkqS0fctcmZotJGhnxkIyJWvBXgpyi2wsFd4J8VB7wzyrT6Ch/3Q+FMNJpjK4gu1+GN5khOnpU2ZVKrLbhCw== + dependencies: + timsort "^0.3.0" + +css-modules-loader-core@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz#5908668294a1becd261ae0a4ce21b0b551f21d16" + integrity sha1-WQhmgpShvs0mGuCkziGwtVHyHRY= + dependencies: + icss-replace-symbols "1.1.0" + postcss "6.0.1" + postcss-modules-extract-imports "1.1.0" + postcss-modules-local-by-default "1.2.0" + postcss-modules-scope "1.1.0" + postcss-modules-values "1.3.0" + +css-select@^4.1.3: + version "4.2.1" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.2.1.tgz#9e665d6ae4c7f9d65dbe69d0316e3221fb274cdd" + integrity sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ== + dependencies: + boolbase "^1.0.0" + css-what "^5.1.0" + domhandler "^4.3.0" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-selector-tokenizer@^0.7.0: + version "0.7.3" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" + integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg== + dependencies: + cssesc "^3.0.0" + fastparse "^1.1.2" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe" + integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^5.1.10: + version "5.1.10" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.10.tgz#9350765fdf3c49bf78fac7673354fa58fa95daa4" + integrity sha512-BcpSzUVygHMOnp9uG5rfPzTOCb0GAHQkqtUQx8j1oMNF9A1Q8hziOOhiM4bdICpmrBIU85BE64RD5XGYsVQZNA== + dependencies: + css-declaration-sorter "^6.0.3" + cssnano-utils "^3.0.0" + postcss-calc "^8.2.0" + postcss-colormin "^5.2.3" + postcss-convert-values "^5.0.2" + postcss-discard-comments "^5.0.1" + postcss-discard-duplicates "^5.0.1" + postcss-discard-empty "^5.0.1" + postcss-discard-overridden "^5.0.2" + postcss-merge-longhand "^5.0.4" + postcss-merge-rules "^5.0.4" + postcss-minify-font-values "^5.0.2" + postcss-minify-gradients "^5.0.4" + postcss-minify-params "^5.0.3" + postcss-minify-selectors "^5.1.1" + postcss-normalize-charset "^5.0.1" + postcss-normalize-display-values "^5.0.2" + postcss-normalize-positions "^5.0.2" + postcss-normalize-repeat-style "^5.0.2" + postcss-normalize-string "^5.0.2" + postcss-normalize-timing-functions "^5.0.2" + postcss-normalize-unicode "^5.0.2" + postcss-normalize-url "^5.0.4" + postcss-normalize-whitespace "^5.0.2" + postcss-ordered-values "^5.0.3" + postcss-reduce-initial "^5.0.2" + postcss-reduce-transforms "^5.0.2" + postcss-svgo "^5.0.3" + postcss-unique-selectors "^5.0.2" + +cssnano-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.0.0.tgz#c0b9fcd6e4f05c5155b07e9ab11bf94b97163057" + integrity sha512-Pzs7/BZ6OgT+tXXuF12DKR8SmSbzUeVYCtMBbS8lI0uAm3mrYmkyqCXXPsQESI6kmLfEVBppbdVY/el3hg3nAA== + +cssnano@^5.0.5, cssnano@^5.0.8: + version "5.0.15" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.15.tgz#8779eaf60e3665e6a12687c814d375cc9f78db76" + integrity sha512-ppZsS7oPpi2sfiyV5+i+NbB/3GtQ+ab2Vs1azrZaXWujUSN4o+WdTxlCZIMcT9yLW3VO/5yX3vpyDaQ1nIn8CQ== + dependencies: + cssnano-preset-default "^5.1.10" + lilconfig "^2.0.3" + yaml "^1.10.2" + +csso@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +cssom@0.3.x, cssom@^0.3.4: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" + integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== + dependencies: + cssom "0.3.x" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-urls@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== + dependencies: + abab "^2.0.0" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.1.0: + 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" + +deep-is@~0.1.3: + 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== + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dom-serializer@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +domain-browser@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-3.5.0.tgz#3a11f5df52fd9d60d7f1c79a62fde2d158c42b09" + integrity sha512-zrzUu6auyZWRexjCEPJnfWc30Hupxh2lJZOJAF3qa2bCuD4O/55t0FvQt3ZMhEw++gjNkwdkOVZh8yA32w/Vfw== + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== + dependencies: + webidl-conversions "^4.0.2" + +domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.0.tgz#16c658c626cf966967e306f966b431f77d4a5626" + integrity sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g== + dependencies: + domelementtype "^2.2.0" + +domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dotenv-expand@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" + integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== + +dotenv@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" + integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +ejs@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a" + integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw== + dependencies: + jake "^10.6.1" + +electron-to-chromium@^1.4.17: + version "1.4.34" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.34.tgz#7d87dc0e95c2c65cbd0687ae23146a662506d1ef" + integrity sha512-B7g6Y9No9XMYk1VNrQ8KAmSEo1Iltrz/5EjOGxl1DffQAb3z/XbpHRCfYKwV8D+CPXm4Q7Xg1sceSt9osNwRIA== + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +emphasize@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/emphasize/-/emphasize-4.2.0.tgz#6b6fdc4d212cb7eafea1c7cdd595dfd6cfc508d9" + integrity sha512-yGKvcFUHlBsUPwlxTlzKLR8+zhpbitkFOMCUxN8fTJng9bdH3WNzUGkhdaGdjndSUgqmMPBN7umfwnUdLz5Axg== + dependencies: + chalk "^4.0.0" + highlight.js "~10.4.0" + lowlight "~1.17.0" + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" + integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.18.5: + 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.4" + is-negative-zero "^2.0.1" + 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" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es6-object-assign@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" + integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw= + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.2, 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= + +escodegen@^1.11.0: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estraverse@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.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: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.1.1.tgz#87ee30e9e9f3eb40d6f254a7997655da753d7c82" + integrity sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + +fast-glob@^3.2.9: + 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" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fast-url-parser@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= + dependencies: + punycode "^1.3.2" + +fastest-levenshtein@^1.0.8: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" + integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== + +fastparse@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" + integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== + +fastq@^1.6.0: + 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" + +fault@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" + integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== + dependencies: + format "^0.2.0" + +filelist@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b" + integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ== + dependencies: + minimatch "^3.0.4" + +filesize@^6.1.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.4.0.tgz#914f50471dd66fdca3cefe628bd0cde4ef769bcd" + integrity sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +follow-redirects@^1.0.0: + version "1.14.7" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" + integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +format@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" + integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +generic-names@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872" + integrity sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ== + dependencies: + loader-utils "^1.1.0" + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-port@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" + integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== + +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" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^5.1.0, glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.1.3, glob@^7.1.4, glob@^7.1.7: + 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" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.2.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.12.0.tgz#4d733760304230a0082ed96e21e5c565f898089e" + integrity sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.3: + 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.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.2.4: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + 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" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +highlight.js@~10.4.0: + version "10.4.1" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.4.1.tgz#d48fbcf4a9971c4361b3f95f302747afe19dbad0" + integrity sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== + dependencies: + whatwg-encoding "^1.0.1" + +html-tags@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-1.2.0.tgz#c78de65b5663aa597989dd2b7ab49200d7e4db98" + integrity sha1-x43mW1Zjqll5id0rerSSANfk25g= + +htmlnano@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-1.1.1.tgz#aea50e1d7ac156370ea766d4cd75f2d3d1a953cc" + integrity sha512-diMNyqTPx4uGwlxrTs0beZCy8L/GxGIFGHWv20OYhthLcdYkDOP/d4Ja5MbGgVJZMakZUM21KpMk5qWZrBGSdw== + dependencies: + cosmiconfig "^7.0.1" + cssnano "^5.0.8" + postcss "^8.3.6" + posthtml "^0.16.5" + purgecss "^4.0.0" + relateurl "^0.2.7" + srcset "^4.0.0" + svgo "^2.6.1" + terser "^5.8.0" + timsort "^0.3.0" + uncss "^0.17.3" + +htmlparser2@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5" + integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.2" + domutils "^2.8.0" + entities "^3.0.1" + +http-proxy-middleware@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-1.3.1.tgz#43700d6d9eecb7419bf086a128d0f7205d9eb665" + integrity sha512-13eVVDYS4z79w7f1+NPllJtOQFx/FdUW4btIvVRMaRlUY9VGstAbo5MOhLEuUgZFRHn3x50ufn25zkj/boZnEg== + dependencies: + "@types/http-proxy" "^1.17.5" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-replace-symbols@1.1.0, icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= + +icss-utils@^4.0.0, icss-utils@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" + integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== + dependencies: + postcss "^7.0.14" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +iferr@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-1.0.2.tgz#e9fde49a9da06dc4a4194c6c9ed6d08305037a6d" + integrity sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg== + +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== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +is-absolute-url@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-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== + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, 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" + +is-html@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-html/-/is-html-1.1.0.tgz#e04f1c18d39485111396f9a0273eab51af218464" + integrity sha1-4E8cGNOUhRETlvmgJz6rUa8hhGQ= + dependencies: + html-tags "^1.0.0" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-json@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff" + integrity sha1-a+Fm0USCihMdaGiRuYPfYsOUkf8= + +is-nan@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +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== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +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-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== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.3, is-typed-array@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" + integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.18.5" + foreach "^2.0.5" + has-tostringtag "^1.0.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-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-url@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== + +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.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +jake@^10.6.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" + integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== + dependencies: + async "0.9.x" + chalk "^2.4.2" + filelist "^1.0.1" + minimatch "^3.0.4" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-14.1.0.tgz#916463b6094956b0a6c1782c94e380cd30e1981b" + integrity sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng== + dependencies: + abab "^2.0.0" + acorn "^6.0.4" + acorn-globals "^4.3.0" + array-equal "^1.0.0" + cssom "^0.3.4" + cssstyle "^1.1.1" + data-urls "^1.1.0" + domexception "^1.0.1" + escodegen "^1.11.0" + html-encoding-sniffer "^1.0.2" + nwsapi "^2.1.3" + parse5 "5.1.0" + pn "^1.1.0" + request "^2.88.0" + request-promise-native "^1.0.5" + saxes "^3.1.9" + symbol-tree "^3.2.2" + tough-cookie "^2.5.0" + w3c-hr-time "^1.0.1" + w3c-xmlserializer "^1.1.2" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^7.0.0" + ws "^6.1.2" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.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-source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/json-source-map/-/json-source-map-0.6.1.tgz#e0b1f6f4ce13a9ad57e2ae165a24d06e62c79a0f" + integrity sha512-1QoztHPsMQqhDq0hlXY5ZqcEdUzxQEIxgFkKl4WUp2pgShObl+9ovi4kRh2TfvAfxAoHOJ9vIMEqk3k4iex7tg== + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^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.0, json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +jsprim@^1.2.2: + 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.4.0" + verror "1.10.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lilconfig@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" + integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lmdb@^2.0.2: + version "2.1.5" + resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.1.5.tgz#7863d268c579b4c6bf6042a97784fe1dea6753d8" + integrity sha512-J84gtJYC6DnZvczrtBF20xIyT9dZzY24/p1wi5zHldyoW+nKuckFy+AywoiMnTBRODp/lJkNhmjqw0dQUl0pFg== + dependencies: + msgpackr "^1.5.2" + nan "^2.14.2" + node-gyp-build "^4.2.3" + ordered-binary "^1.2.3" + weak-lru-cache "^1.2.1" + +loader-utils@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + +lodash.clone@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" + integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.15, lodash@^4.17.19: + 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" + +lowlight@~1.17.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.17.0.tgz#a1143b2fba8239df8cd5893f9fe97aaf8465af4a" + integrity sha512-vmtBgYKD+QVNy7tIa7ulz5d//Il9R4MooOVh4nkOf9R9Cb/Dk5TXMSTieg/vDulkBkIWj59/BIlyFQxT9X1oAQ== + dependencies: + fault "^1.0.0" + highlight.js "~10.4.0" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +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== + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.51.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.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + +mime-types@^2.1.12, mime-types@~2.1.19: + 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" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@3.0.4, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +msgpackr-extract@^1.0.14: + version "1.0.16" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-1.0.16.tgz#701c4f6e6f25c100ae84557092274e8fffeefe45" + integrity sha512-fxdRfQUxPrL/TizyfYfMn09dK58e+d65bRD/fcaVH4052vj30QOzzqxcQIS7B0NsqlypEQ/6Du3QmP2DhWFfCA== + dependencies: + nan "^2.14.2" + node-gyp-build "^4.2.3" + +msgpackr@^1.5.1, msgpackr@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.5.2.tgz#b400c9885642bdec27b284f8bdadbd6570b448b7" + integrity sha512-OCguCkbG34x1ddO4vAzEm/4J1GTo512k9SoxV8K+EGfI/onFdpemRf0HpsVRFpxadXr4JBFgHsQUitgTlw7ZYQ== + optionalDependencies: + msgpackr-extract "^1.0.14" + +nan@^2.14.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.30: + version "3.2.0" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c" + integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA== + +ncp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-addon-api@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-forge@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.2.1.tgz#82794919071ef2eb5c509293325cec8afd0fd53c" + integrity sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w== + +node-gyp-build@^4.2.3, node-gyp-build@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" + integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + +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== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +nth-check@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== + dependencies: + boolbase "^1.0.0" + +nullthrows@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" + integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== + +nwsapi@^2.1.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-inspect@^1.11.0, object-inspect@^1.9.0: + 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-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^7.0.3: + version "7.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +ora@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +ordered-binary@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.2.3.tgz#518f637692a74d372e56230effae37b811575e36" + integrity sha512-fEwMk8TNUtzQDjXKYS2ANW3fNZ/gMReCPOAsLHaqw+UDnq/8ddXAcX4lGRpTK7kAghAjkmJs1EXXbcrDbg+ruw== + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parcel@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.2.0.tgz#43bf0c7f050417a397d7c30b4e890cfb105b4246" + integrity sha512-oyjPko23uBZZa5ihJP65CeSbO4Nmb7mj8sPU8XQbYeBOtFoSHJf9KfQ6WCy0d7gXXkXSEXdBGH18uydWoLm9AQ== + dependencies: + "@parcel/config-default" "^2.2.0" + "@parcel/core" "^2.2.0" + "@parcel/diagnostic" "^2.2.0" + "@parcel/events" "^2.2.0" + "@parcel/fs" "^2.2.0" + "@parcel/logger" "^2.2.0" + "@parcel/package-manager" "^2.2.0" + "@parcel/reporter-cli" "^2.2.0" + "@parcel/reporter-dev-server" "^2.2.0" + "@parcel/utils" "^2.2.0" + chalk "^4.1.0" + commander "^7.0.0" + get-port "^4.2.0" + v8-compile-cache "^2.0.0" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^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" + +parse5@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" + integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-browserify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-to-regexp@2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" + integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +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.2.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== + +postcss-calc@^8.2.0: + version "8.2.2" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.2.tgz#9706e7399e8ec8b61a47830dcf1f21391af23373" + integrity sha512-B5R0UeB4zLJvxNt1FVCaDZULdzsKLPc6FhjFJ+xwFiq7VG4i9cuaJLxVjNtExNK8ocm3n2o4unXXLiVX1SCqxA== + dependencies: + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-colormin@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.3.tgz#da7fb80e81ad80d2867ea9e38672a892add5df15" + integrity sha512-dra4xoAjub2wha6RUXAgadHEn2lGxbj8drhFcIGLOMn914Eu7DkPUurugDXgstwttCYkJtZ/+PkWRWdp3UHRIA== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + colord "^2.9.1" + postcss-value-parser "^4.2.0" + +postcss-convert-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz#879b849dc3677c7d6bc94b6a2c1a3f0808798059" + integrity sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg== + dependencies: + postcss-value-parser "^4.1.0" + +postcss-discard-comments@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe" + integrity sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg== + +postcss-discard-duplicates@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz#68f7cc6458fe6bab2e46c9f55ae52869f680e66d" + integrity sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA== + +postcss-discard-empty@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz#ee136c39e27d5d2ed4da0ee5ed02bc8a9f8bf6d8" + integrity sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw== + +postcss-discard-overridden@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.2.tgz#e6f51d83e66feffcf05ed94c4ad20b814d0aab5f" + integrity sha512-+56BLP6NSSUuWUXjRgAQuho1p5xs/hU5Sw7+xt9S3JSg+7R6+WMGnJW7Hre/6tTuZ2xiXMB42ObkiZJ2hy/Pew== + +postcss-merge-longhand@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" + integrity sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw== + dependencies: + postcss-value-parser "^4.1.0" + stylehacks "^5.0.1" + +postcss-merge-rules@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.4.tgz#a50640fd832380f322bd2861a9b33fbde4219f9b" + integrity sha512-yOj7bW3NxlQxaERBB0lEY1sH5y+RzevjbdH4DBJurjKERNpknRByFNdNe+V72i5pIZL12woM9uGdS5xbSB+kDQ== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + cssnano-utils "^3.0.0" + postcss-selector-parser "^6.0.5" + +postcss-minify-font-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.2.tgz#4603e956d85cd0719156e2b3eb68e3cd2f917092" + integrity sha512-R6MJZryq28Cw0AmnyhXrM7naqJZZLoa1paBltIzh2wM7yb4D45TLur+eubTQ4jCmZU9SGeZdWsc5KcSoqTMeTg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-minify-gradients@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.4.tgz#f13146950513f5a201015306914e3c76d10b591d" + integrity sha512-RVwZA7NC4R4J76u8X0Q0j+J7ItKUWAeBUJ8oEEZWmtv3Xoh19uNJaJwzNpsydQjk6PkuhRrK+YwwMf+c+68EYg== + dependencies: + colord "^2.9.1" + cssnano-utils "^3.0.0" + postcss-value-parser "^4.2.0" + +postcss-minify-params@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.3.tgz#9f933d37098ef1dcf007e159a47bb2c1cf06989d" + integrity sha512-NY92FUikE+wralaiVexFd5gwb7oJTIDhgTNeIw89i1Ymsgt4RWiPXfz3bg7hDy4NL6gepcThJwOYNtZO/eNi7Q== + dependencies: + alphanum-sort "^1.0.2" + browserslist "^4.16.6" + cssnano-utils "^3.0.0" + postcss-value-parser "^4.2.0" + +postcss-minify-selectors@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.1.tgz#20ae03b411f7fb397451e3d7d85b989f944b871c" + integrity sha512-TOzqOPXt91O2luJInaVPiivh90a2SIK5Nf1Ea7yEIM/5w+XA5BGrZGUSW8aEx9pJ/oNj7ZJBhjvigSiBV+bC1Q== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + +postcss-modules-extract-imports@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz#b614c9720be6816eaee35fb3a5faa1dba6a05ddb" + integrity sha1-thTJcgvmgW6u41+zpfqh26agXds= + dependencies: + postcss "^6.0.1" + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" + integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk= + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-local-by-default@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" + integrity sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw== + dependencies: + icss-utils "^4.1.1" + postcss "^7.0.32" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" + integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A= + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-scope@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" + integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-values@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" + integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA= + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^6.0.1" + +postcss-modules-values@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" + integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== + dependencies: + icss-utils "^4.0.0" + postcss "^7.0.6" + +postcss-modules@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-3.2.2.tgz#ee390de0f9f18e761e1778dfb9be26685c02c51f" + integrity sha512-JQ8IAqHELxC0N6tyCg2UF40pACY5oiL6UpiqqcIFRWqgDYO8B0jnxzoQ0EOpPrWXvcpu6BSbQU/3vSiq7w8Nhw== + dependencies: + generic-names "^2.0.1" + icss-replace-symbols "^1.1.0" + lodash.camelcase "^4.3.0" + postcss "^7.0.32" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^3.0.2" + postcss-modules-scope "^2.2.0" + postcss-modules-values "^3.0.0" + string-hash "^1.1.1" + +postcss-normalize-charset@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0" + integrity sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg== + +postcss-normalize-display-values@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.2.tgz#8b5273c6c7d0a445e6ef226b8a5bb3204a55fb99" + integrity sha512-RxXoJPUR0shSjkMMzgEZDjGPrgXUVYyWA/YwQRicb48H15OClPuaDR7tYokLAlGZ2tCSENEN5WxjgxSD5m4cUw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-positions@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.0.2.tgz#799fa494b352a5da183be8f050024af6d92fa29c" + integrity sha512-tqghWFVDp2btqFg1gYob1etPNxXLNh3uVeWgZE2AQGh6b2F8AK2Gj36v5Vhyh+APwIzNjmt6jwZ9pTBP+/OM8g== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-repeat-style@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.2.tgz#fd9bddba3e6fd5f5d95c18dfb42a09ecd563adea" + integrity sha512-/rIZn8X9bBzC7KvY4iKUhXUGW3MmbXwfPF23jC9wT9xTi7kAvgj8sEgwxjixBmoL6MVa4WOgxNz2hAR6wTK8tw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-string@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.0.2.tgz#1b2bbf91526f61266f28abf7f773e4136b2c4bd2" + integrity sha512-zaI1yzwL+a/FkIzUWMQoH25YwCYxi917J4pYm1nRXtdgiCdnlTkx5eRzqWEC64HtRa06WCJ9TIutpb6GmW4gFw== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-timing-functions@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.2.tgz#db4f4f49721f47667afd1fdc5edb032f8d9cdb2e" + integrity sha512-Ao0PP6MoYsRU1LxeVUW740ioknvdIUmfr6uAA3xWlQJ9s69/Tupy8qwhuKG3xWfl+KvLMAP9p2WXF9cwuk/7Bg== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-normalize-unicode@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.2.tgz#c4db89a0116066716b9e9fcb6444ce63178f5ced" + integrity sha512-3y/V+vjZ19HNcTizeqwrbZSUsE69ZMRHfiiyLAJb7C7hJtYmM4Gsbajy7gKagu97E8q5rlS9k8FhojA8cpGhWw== + dependencies: + browserslist "^4.16.6" + postcss-value-parser "^4.2.0" + +postcss-normalize-url@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.4.tgz#3b0322c425e31dd275174d0d5db0e466f50810fb" + integrity sha512-cNj3RzK2pgQQyNp7dzq0dqpUpQ/wYtdDZM3DepPmFjCmYIfceuD9VIAcOdvrNetjIU65g1B4uwdP/Krf6AFdXg== + dependencies: + normalize-url "^6.0.1" + postcss-value-parser "^4.2.0" + +postcss-normalize-whitespace@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.2.tgz#92c5eaffe5255b5c43fca0baf19227e607c534db" + integrity sha512-CXBx+9fVlzSgbk0IXA/dcZn9lXixnQRndnsPC5ht3HxlQ1bVh77KQDL1GffJx1LTzzfae8ftMulsjYmO2yegxA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-ordered-values@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.3.tgz#d80a8565f2e21efe8a06abacd60629a783bbcf54" + integrity sha512-T9pDS+P9bWeFvqivXd5ACzQmrCmHjv3ZP+djn8E1UZY7iK79pFSm7i3WbKw2VSmFmdbMm8sQ12OPcNpzBo3Z2w== + dependencies: + cssnano-utils "^3.0.0" + postcss-value-parser "^4.2.0" + +postcss-reduce-initial@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz#fa424ce8aa88a89bc0b6d0f94871b24abe94c048" + integrity sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw== + dependencies: + browserslist "^4.16.6" + caniuse-api "^3.0.0" + +postcss-reduce-transforms@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.2.tgz#9242758629f9ad4d90312eadbc921259d15bee4d" + integrity sha512-25HeDeFsgiPSUx69jJXZn8I06tMxLQJJNF5h7i9gsUg8iP4KOOJ8EX8fj3seeoLt3SLU2YDD6UPnDYVGUO7DEA== + dependencies: + postcss-value-parser "^4.2.0" + +postcss-selector-parser@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + dependencies: + cssesc "^3.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.6: + 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-svgo@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.3.tgz#d945185756e5dfaae07f9edb0d3cae7ff79f9b30" + integrity sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA== + dependencies: + postcss-value-parser "^4.1.0" + svgo "^2.7.0" + +postcss-unique-selectors@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz#5d6893daf534ae52626708e0d62250890108c0c1" + integrity sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA== + dependencies: + alphanum-sort "^1.0.2" + postcss-selector-parser "^6.0.5" + +postcss-value-parser@^4.0.2, 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@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.1.tgz#000dbd1f8eef217aa368b9a212c5fc40b2a8f3f2" + integrity sha1-AA29H47vIXqjaLmiEsX8QLKo8/I= + dependencies: + chalk "^1.1.3" + source-map "^0.5.6" + supports-color "^3.2.3" + +postcss@^6.0.1: + version "6.0.23" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" + integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== + dependencies: + chalk "^2.4.1" + source-map "^0.6.1" + supports-color "^5.4.0" + +postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.3.0, postcss@^8.3.5, postcss@^8.3.6: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + +posthtml-parser@^0.10.0, posthtml-parser@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.1.tgz#63c41931a9339cc2c32aba14f06286d98f107abf" + integrity sha512-i7w2QEHqiGtsvNNPty0Mt/+ERch7wkgnFh3+JnBI2VgDbGlBqKW9eDVd3ENUhE1ujGFe3e3E/odf7eKhvLUyDg== + dependencies: + htmlparser2 "^7.1.1" + +posthtml-render@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205" + integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA== + dependencies: + is-json "^2.0.1" + +posthtml@^0.16.4, posthtml@^0.16.5: + version "0.16.5" + resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.5.tgz#d32f5cf32436516d49e0884b2367d0a1424136f6" + integrity sha512-1qOuPsywVlvymhTFIBniDXwUDwvlDri5KUQuBqjmCc8Jj4b/HDSVWU//P6rTWke5rzrk+vj7mms2w8e1vD0nnw== + dependencies: + posthtml-parser "^0.10.0" + posthtml-render "^3.0.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.3.2, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +purgecss@^4.0.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-4.1.3.tgz#683f6a133c8c4de7aa82fe2746d1393b214918f7" + integrity sha512-99cKy4s+VZoXnPxaoM23e5ABcP851nC2y2GROkkjS8eJaJtlciGavd7iYAw2V84WeBqggZ12l8ef44G99HmTaw== + dependencies: + commander "^8.0.0" + glob "^7.1.7" + postcss "^8.3.5" + postcss-selector-parser "^6.0.6" + +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== + +querystring-es3@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +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== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +react-refresh@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" + integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== + +"readable-stream@1 || 2": + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.0, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +regenerator-runtime@^0.13.7: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +request-promise-core@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" + integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== + dependencies: + lodash "^4.17.19" + +request-promise-native@^1.0.5: + version "1.0.9" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" + integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== + dependencies: + request-promise-core "1.1.4" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-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== + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saxes@^3.1.9: + version "3.1.11" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" + integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== + dependencies: + xmlchars "^2.1.1" + +semver@^5.5.0, semver@^5.7.0, semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +serve-handler@^6.0.0: + version "6.1.3" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8" + integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w== + dependencies: + bytes "3.0.0" + content-disposition "0.5.2" + fast-url-parser "1.1.3" + mime-types "2.1.18" + minimatch "3.0.4" + path-is-inside "1.0.2" + path-to-regexp "2.2.1" + range-parser "1.2.0" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2: + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +source-map-js@^1.0.1: + 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-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.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.7.2: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +split2@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" + integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== + dependencies: + readable-stream "^3.0.0" + +srcset@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4" + integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw== + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-http@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5" + integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.4" + readable-stream "^3.6.0" + xtend "^4.0.2" + +string-hash@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" + integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= + +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.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.1.1, string_decoder@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^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.1" + +stylehacks@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" + integrity sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA== + dependencies: + browserslist "^4.16.0" + postcss-selector-parser "^6.0.4" + +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= + +supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0, supports-color@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +svgo@^2.4.0, svgo@^2.6.1, svgo@^2.7.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + +symbol-tree@^3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +term-size@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== + +terminal-link@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +terser@^5.2.0, terser@^5.8.0: + 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.20" + +timers-browserify@^2.0.11: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tough-cookie@^2.3.3, tough-cookie@^2.5.0, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + +tty-browserify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "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== + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +uncss@^0.17.3: + version "0.17.3" + resolved "https://registry.yarnpkg.com/uncss/-/uncss-0.17.3.tgz#50fc1eb4ed573ffff763458d801cd86e4d69ea11" + integrity sha512-ksdDWl81YWvF/X14fOSw4iu8tESDHFIeyKIeDrK6GEVTQvqJc1WlOEXqostNwOCi3qAj++4EaLsdAgPmUbEyog== + dependencies: + commander "^2.20.0" + glob "^7.1.4" + is-absolute-url "^3.0.1" + is-html "^1.1.0" + jsdom "^14.1.0" + lodash "^4.17.15" + postcss "^7.0.17" + postcss-selector-parser "6.0.2" + request "^2.88.0" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +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" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@^0.12.0, util@^0.12.3: + version "0.12.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" + integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + +utility-types@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" + integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2: + 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.0: + 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== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +w3c-hr-time@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" + integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== + dependencies: + domexception "^1.0.1" + webidl-conversions "^4.0.2" + xml-name-validator "^3.0.0" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +weak-lru-cache@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.1.tgz#6b4f2da7e1701f845e71522417f1df1e39503df8" + integrity sha512-O5ag1F0Xk6ui+Fg5LlosTcVAyHs6DeyiDDbOapNtFCx/KjZ82B3U9stM9hvzbVclKWn9ABPjaINX/nQkGkJkKg== + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.2: + version "1.1.7" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" + integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.18.5" + foreach "^2.0.5" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.7" + +which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@^6.1.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== + dependencies: + async-limiter "~1.0.0" + +ws@^7.0.0: + version "7.5.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +xxhash-wasm@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79" + integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.0, yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== From cbcff0d2d2eac0da94e9b2fca128e591eec49f13 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 12:36:06 +0100 Subject: [PATCH 05/60] Fix GHA workflow --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c43dac7d..68c930b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,9 +5,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - uses: olafurpg/setup-scala@v11 + - uses: olafurpg/setup-scala@v14 with: - java-version: adopt@1.19 + java-version: adopt@1.17 - uses: jodersky/setup-mill@master with: mill-version: 0.10.12 From 2e4c23dbbf92635e3765c5197bef476fdb3f425f Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 12:39:06 +0100 Subject: [PATCH 06/60] Try again --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68c930b2..4b374441 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: - uses: actions/checkout@v1 - uses: olafurpg/setup-scala@v14 with: - java-version: adopt@1.17 + java-version: adopt@1.11 - uses: jodersky/setup-mill@master with: mill-version: 0.10.12 From 414b5a1c3c4c669a5c5ccc67f1be387c5d79bf15 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 12:41:06 +0100 Subject: [PATCH 07/60] Change base package --- ui/ui/src/{example => vgb}/Main.scala | 2 ++ ui/ui/test/src/{example => vgb}/SiteTests.scala | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) rename ui/ui/src/{example => vgb}/Main.scala (98%) rename ui/ui/test/src/{example => vgb}/SiteTests.scala (91%) diff --git a/ui/ui/src/example/Main.scala b/ui/ui/src/vgb/Main.scala similarity index 98% rename from ui/ui/src/example/Main.scala rename to ui/ui/src/vgb/Main.scala index a3aecfcb..30be9858 100644 --- a/ui/ui/src/example/Main.scala +++ b/ui/ui/src/vgb/Main.scala @@ -1,3 +1,5 @@ +package vgb + import cats.effect.IO import tyrian.Html.* import tyrian.* diff --git a/ui/ui/test/src/example/SiteTests.scala b/ui/ui/test/src/vgb/SiteTests.scala similarity index 91% rename from ui/ui/test/src/example/SiteTests.scala rename to ui/ui/test/src/vgb/SiteTests.scala index 29b654f4..ad56eef1 100644 --- a/ui/ui/test/src/example/SiteTests.scala +++ b/ui/ui/test/src/vgb/SiteTests.scala @@ -1,4 +1,4 @@ - +package vgb import cats.effect.IO class SiteTests extends munit.FunSuite { From 699bbd146e597df5296ce945b362e273d6561807 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 13:03:11 +0100 Subject: [PATCH 08/60] Ported Colour class --- ui/ui/src/vgb/Colour.scala | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 ui/ui/src/vgb/Colour.scala diff --git a/ui/ui/src/vgb/Colour.scala b/ui/ui/src/vgb/Colour.scala new file mode 100644 index 00000000..4bca9697 --- /dev/null +++ b/ui/ui/src/vgb/Colour.scala @@ -0,0 +1,34 @@ +package vgb + +final case class Colour(red: Int, green: Int, blue: Int, alpha: Int) + +object Colour: + val red: Colour = Colour(255, 0, 0, 1) + val green: Colour = Colour(0, 128, 0, 1) + val blue: Colour = Colour(0, 0, 255, 1) + val yellow: Colour = Colour(255, 255, 0, 1) + val orange: Colour = Colour(255, 165, 0, 1) + val indigo: Colour = Colour(75, 0, 130, 1) + + def toHexString(colour: Colour): String = + "#" + + (colour.red.toHexString.reverse.padTo(2, '0').reverse) + + (colour.green.toHexString.reverse.padTo(2, '0').reverse) + + (colour.blue.toHexString.reverse.padTo(2, '0').reverse) + + def toRGBAString(colour: Colour): String = + s"rgba(${colour.red.toString()}, ${colour.green.toString()}, ${colour.blue.toString()}, ${colour.alpha.toString()})" + + def fromHexString(str: String): Colour = + val strNoHash = str.replaceAll("#", "") + + Colour( + hexToInt(strNoHash.take(2)), + hexToInt(strNoHash.drop(2).take(2)), + hexToInt(strNoHash.drop(4).take(2)), + if strNoHash.length > 6 then hexToInt(strNoHash.drop(6).take(2)) + else 1 + ) + + def hexToInt(hex: String): Int = + Integer.parseInt(hex, 16) From 0642ce632cf72d88769c4143fb1e97f079c47a06 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 15:07:52 +0100 Subject: [PATCH 09/60] Ported Hexagon class --- ui/ui/src/vgb/Hexagon.scala | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 ui/ui/src/vgb/Hexagon.scala diff --git a/ui/ui/src/vgb/Hexagon.scala b/ui/ui/src/vgb/Hexagon.scala new file mode 100644 index 00000000..7b733068 --- /dev/null +++ b/ui/ui/src/vgb/Hexagon.scala @@ -0,0 +1,33 @@ +package vgb + +object Hexagon: + + def rotate(origin: (Int, Int), rotationPoint: (Int, Int), numTurns: Int): (Int, Int) = + val rotateResult = singleRotate(origin, rotationPoint) + + numTurns match + case 0 => + origin + + case 1 => + rotateResult + + case other if other < 0 => + rotate(rotateResult, rotationPoint, other + 1) + + case other => + rotate(rotateResult, rotationPoint, other - 1) + + def singleRotate(origin: (Int, Int), rotationPoint: (Int, Int)): (Int, Int) = + val (originX, originY, originZ) = oddRowToCube(origin._1, origin._2) + val (rotateX, rotateY, rotateZ) = oddRowToCube(rotationPoint._1, rotationPoint._2) + val (rX, rY, rZ) = (-(originZ - rotateZ), -(originX - rotateX), -(originY - rotateY)) + + cubeToOddRow(rX + rotateX, rY + rotateY, rZ + rotateZ) + + def cubeToOddRow(x: Int, y: Int, z: Int): (Int, Int) = + (x + (z - (z & 1)), z) + + def oddRowToCube(x: Int, y: Int): (Int, Int, Int) = + val newX = x - (y - (y & 1)) + (newX, -newX - y, y) From 5f34b588d6d04b21542ef563f0c647b650b6a5b5 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 15:45:36 +0100 Subject: [PATCH 10/60] Ported BoardMapTile class --- ui/ui/src/vgb/BoardMapTile.scala | 393 +++++++++++++++++++++++++++++++ 1 file changed, 393 insertions(+) create mode 100644 ui/ui/src/vgb/BoardMapTile.scala diff --git a/ui/ui/src/vgb/BoardMapTile.scala b/ui/ui/src/vgb/BoardMapTile.scala new file mode 100644 index 00000000..ec0c78bf --- /dev/null +++ b/ui/ui/src/vgb/BoardMapTile.scala @@ -0,0 +1,393 @@ +package vgb + +object BoardMapTile: + + def getMapTileListByRef(ref: MapTileRef): List[MapTile] = + getGridByRef(ref).zipWithIndex.flatMap { case (lb, y) => + indexedArrayYToMapTile(ref, y, lb) + } + + def refToString(ref: MapTileRef): Option[String] = + boardRefDict.toList.filter(_ == ref).headOption.map(_._1) + + def stringToRef(ref: String): Option[MapTileRef] = + boardRefDict.get(ref.toLowerCase()) + + val getAllRefs: List[MapTileRef] = + boardRefDict.values.toList.filterNot(_ == MapTileRef.Empty) + + def indexedArrayYToMapTile(ref: MapTileRef, y: Int, arr: List[Boolean]): List[MapTile] = + arr.zipWithIndex.map { case (p, x) => + indexedArrayXToMapTile(ref, y, x, p) + } + + def indexedArrayXToMapTile(ref: MapTileRef, y: Int, x: Int, passable: Boolean): MapTile = + MapTile(ref, x, y, 0, x, y, passable, true) + + val boardRefDict: Map[String, MapTileRef] = + Map( + ("a1a", MapTileRef.A1a), + ("a1b", MapTileRef.A1b), + ("a2a", MapTileRef.A2a), + ("a2b", MapTileRef.A2b), + ("a3a", MapTileRef.A3a), + ("a3b", MapTileRef.A3b), + ("a4a", MapTileRef.A4a), + ("a4b", MapTileRef.A4b), + ("b1a", MapTileRef.B1a), + ("b1b", MapTileRef.B1b), + ("b2a", MapTileRef.B2a), + ("b2b", MapTileRef.B2b), + ("b3a", MapTileRef.B3a), + ("b3b", MapTileRef.B3b), + ("b4a", MapTileRef.B4a), + ("b4b", MapTileRef.B4b), + ("c1a", MapTileRef.C1a), + ("c1b", MapTileRef.C1b), + ("c2a", MapTileRef.C2a), + ("c2b", MapTileRef.C2b), + ("d1a", MapTileRef.D1a), + ("d1b", MapTileRef.D1b), + ("d2a", MapTileRef.D2a), + ("d2b", MapTileRef.D2b), + ("e1a", MapTileRef.E1a), + ("e1b", MapTileRef.E1b), + ("f1a", MapTileRef.F1a), + ("f1b", MapTileRef.F1b), + ("g1a", MapTileRef.G1a), + ("g1b", MapTileRef.G1b), + ("g2a", MapTileRef.G2a), + ("g2b", MapTileRef.G2b), + ("h1a", MapTileRef.H1a), + ("h1b", MapTileRef.H1b), + ("h2a", MapTileRef.H2a), + ("h2b", MapTileRef.H2b), + ("h3a", MapTileRef.H3a), + ("h3b", MapTileRef.H3b), + ("i1a", MapTileRef.I1a), + ("i1b", MapTileRef.I1b), + ("i2a", MapTileRef.I2a), + ("i2b", MapTileRef.I2b), + ("j1a", MapTileRef.J1a), + ("j1b", MapTileRef.J1b), + ("j1ba", MapTileRef.J1ba), + ("j1bb", MapTileRef.J1bb), + ("j2a", MapTileRef.J2a), + ("j2b", MapTileRef.J2b), + ("k1a", MapTileRef.K1a), + ("k1b", MapTileRef.K1b), + ("k2a", MapTileRef.K2a), + ("k2b", MapTileRef.K2b), + ("l1a", MapTileRef.L1a), + ("l1b", MapTileRef.L1b), + ("l2a", MapTileRef.L2a), + ("l2b", MapTileRef.L2b), + ("l3a", MapTileRef.L3a), + ("l3b", MapTileRef.L3b), + ("m1a", MapTileRef.M1a), + ("m1b", MapTileRef.M1b), + ("n1a", MapTileRef.N1a), + ("n1b", MapTileRef.N1b), + ("empty", MapTileRef.Empty) + ) + + def getGridByRef(ref: MapTileRef): List[List[Boolean]] = + + val configA = + List( + List(false, false, false, false, false), + List(true, true, true, true, false), + List(true, true, true, true, true), + List(false, false, false, false, false) + ) + + val configB = + List( + List(true, true, true, true), + List(true, true, true, false), + List(true, true, true, true), + List(true, true, true, false) + ) + + val configC = + List( + List(false, true, true, false), + List(true, true, true, false), + List(true, true, true, true), + List(true, true, true, false) + ) + + val configD = + List( + List(false, true, true, true, false), + List(true, true, true, true, false), + List(true, true, true, true, true), + List(true, true, true, true, false), + List(false, true, true, true, false) + ) + + val configE = + List( + List(false, true, true, true, true), + List(true, true, true, true, true), + List(false, true, true, true, true), + List(true, true, true, true, true), + List(false, true, true, true, true) + ) + + val configF = + List( + List(true, true, true), + List(true, true, false), + List(true, true, true), + List(true, true, false), + List(true, true, true), + List(true, true, false), + List(true, true, true), + List(true, true, false), + List(true, true, true) + ) + + val configG = + List( + List(true, true, true, true, true, true, true, true), + List(true, true, true, true, true, true, true, false), + List(true, true, true, true, true, true, true, true) + ) + + val configH = + List( + List(false, true, true, true, true, true, true), + List(true, true, true, true, true, true, true), + List(false, false, false, true, true, false, false), + List(false, false, true, true, true, false, false), + List(false, false, false, true, true, false, false), + List(false, false, true, true, true, false, false), + List(false, false, false, true, true, false, false) + ) + + val configI = + List( + List(true, true, true, true, true, true), + List(true, true, true, true, true, false), + List(true, true, true, true, true, true), + List(true, true, true, true, true, false), + List(true, true, true, true, true, true) + ) + + val configJ = + List( + List(false, false, false, false, false, false, true, false), + List(false, false, false, false, false, true, true, true), + List(false, false, false, false, false, true, true, true), + List(false, false, false, false, true, true, true, false), + List(true, true, true, true, true, true, true, false), + List(true, true, true, true, true, true, false, false), + List(true, true, true, true, true, false, false, false) + ) + + val configJ1ba = + List( + List(false, false, false, false, false, false, false, false), + List(false, false, false, false, true, true, false, false), + List(false, false, false, false, true, true, true, false), + List(false, false, false, false, true, true, true, false), + List(false, false, false, false, false, true, true, true), + List(false, false, false, false, false, true, false, false), + List(false, false, false, false, false, false, false, false) + ) + + val configJ1bb = + List( + List(true, true, true, true, true, false, false, false), + List(true, true, true, true, false, false, false, false), + List(true, true, true, true, false, false, false, false), + List(false, false, false, false, false, false, false, false), + List(false, false, false, false, false, false, false, false), + List(false, false, false, false, false, false, false, false), + List(false, false, false, false, false, false, false, false) + ) + + val configK = + List( + List(false, false, true, true, true, true, false, false), + List(false, true, true, true, true, true, false, false), + List(false, true, true, true, true, true, true, false), + List(true, true, true, false, true, true, true, false), + List(true, true, true, false, false, true, true, true), + List(true, true, false, false, false, true, true, false) + ) + + val configL = + List( + List(true, true, true, true, true), + List(true, true, true, true, false), + List(true, true, true, true, true), + List(true, true, true, true, false), + List(true, true, true, true, true), + List(true, true, true, true, false), + List(true, true, true, true, true) + ) + + val configM = + List( + List(false, true, true, true, true, false), + List(true, true, true, true, true, false), + List(true, true, true, true, true, true), + List(true, true, true, true, true, false), + List(true, true, true, true, true, true), + List(true, true, true, true, true, false), + List(false, true, true, true, true, false) + ) + + val configN = + List( + List(true, true, true, true, true, true, true, true), + List(true, true, true, true, true, true, true, false), + List(true, true, true, true, true, true, true, true), + List(true, true, true, true, true, true, true, false), + List(true, true, true, true, true, true, true, true), + List(true, true, true, true, true, true, true, false), + List(true, true, true, true, true, true, true, true) + ) + + ref match + case MapTileRef.A1a => configA + case MapTileRef.A1b => configA + case MapTileRef.A2a => configA + case MapTileRef.A2b => configA + case MapTileRef.A3a => configA + case MapTileRef.A3b => configA + case MapTileRef.A4a => configA + case MapTileRef.A4b => configA + case MapTileRef.B1a => configB + case MapTileRef.B1b => configB + case MapTileRef.B2a => configB + case MapTileRef.B2b => configB + case MapTileRef.B3a => configB + case MapTileRef.B3b => configB + case MapTileRef.B4a => configB + case MapTileRef.B4b => configB + case MapTileRef.C1a => configC + case MapTileRef.C1b => configC + case MapTileRef.C2a => configC + case MapTileRef.C2b => configC + case MapTileRef.D1a => configD + case MapTileRef.D1b => configD + case MapTileRef.D2a => configD + case MapTileRef.D2b => configD + case MapTileRef.E1a => configE + case MapTileRef.E1b => configE + case MapTileRef.F1a => configF + case MapTileRef.F1b => configF + case MapTileRef.G1a => configG + case MapTileRef.G1b => configG + case MapTileRef.G2a => configG + case MapTileRef.G2b => configG + case MapTileRef.H1a => configH + case MapTileRef.H1b => configH + case MapTileRef.H2a => configH + case MapTileRef.H2b => configH + case MapTileRef.H3a => configH + case MapTileRef.H3b => configH + case MapTileRef.I1a => configI + case MapTileRef.I1b => configI + case MapTileRef.I2a => configI + case MapTileRef.I2b => configI + case MapTileRef.J1a => configJ + case MapTileRef.J1b => configJ.reverse + case MapTileRef.J1ba => configJ1ba + case MapTileRef.J1bb => configJ1bb + case MapTileRef.J2a => configJ + case MapTileRef.J2b => configJ.reverse + case MapTileRef.K1a => configK + case MapTileRef.K1b => configK + case MapTileRef.K2a => configK + case MapTileRef.K2b => configK + case MapTileRef.L1a => configL + case MapTileRef.L1b => configL + case MapTileRef.L2a => configL + case MapTileRef.L2b => configL + case MapTileRef.L3a => configL + case MapTileRef.L3b => configL + case MapTileRef.M1a => configM + case MapTileRef.M1b => configM + case MapTileRef.N1a => configN + case MapTileRef.N1b => configN + case MapTileRef.Empty => List(List(true)) + +final case class MapTile( + ref: MapTileRef, + x: Int, + y: Int, + turns: Int, + originalX: Int, + originalY: Int, + passable: Boolean, + hidden: Boolean +) + +enum MapTileRef: + case A1a + case A1b + case A2a + case A2b + case A3a + case A3b + case A4a + case A4b + case B1a + case B1b + case B2a + case B2b + case B3a + case B3b + case B4a + case B4b + case C1a + case C1b + case C2a + case C2b + case D1a + case D1b + case D2a + case D2b + case E1a + case E1b + case F1a + case F1b + case G1a + case G1b + case G2a + case G2b + case H1a + case H1b + case H2a + case H2b + case H3a + case H3b + case I1a + case I1b + case I2a + case I2b + case J1a + case J1b + case J1ba + case J1bb + case J2a + case J2b + case K1a + case K1b + case K2a + case K2b + case L1a + case L1b + case L2a + case L2b + case L3a + case L3b + case M1a + case M1b + case N1a + case N1b + case Empty From 133f0e38e3329d86cbf0c3b43b63ee12e87e96d3 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 15:49:59 +0100 Subject: [PATCH 11/60] Ported Version class --- ui/ui/src/vgb/Version.scala | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ui/ui/src/vgb/Version.scala diff --git a/ui/ui/src/vgb/Version.scala b/ui/ui/src/vgb/Version.scala new file mode 100644 index 00000000..4f0a043b --- /dev/null +++ b/ui/ui/src/vgb/Version.scala @@ -0,0 +1,4 @@ +package vgb + +object Version: + def get: String = "1.15.1" From 12cefff0fb31d52bfefb002e2be8064ceadc5f0e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 16:11:27 +0100 Subject: [PATCH 12/60] Ported Monster class --- ui/ui/src/vgb/Monster.scala | 205 ++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 ui/ui/src/vgb/Monster.scala diff --git a/ui/ui/src/vgb/Monster.scala b/ui/ui/src/vgb/Monster.scala new file mode 100644 index 00000000..0c867259 --- /dev/null +++ b/ui/ui/src/vgb/Monster.scala @@ -0,0 +1,205 @@ +package vgb + +object Monster: + + private val normalDict: Map[String, NormalMonsterType] = + import NormalMonsterType.* + Map( + ("aesther-ashblade", AestherAshblade), + ("aesther-scout", AestherScout), + ("bandit-guard", BanditGuard), + ("bandit-archer", BanditArcher), + ("city-guard", CityGuard), + ("city-archer", CityArcher), + ("inox-guard", InoxGuard), + ("inox-archer", InoxArcher), + ("inox-shaman", InoxShaman), + ("valrath-tracker", ValrathTracker), + ("valrath-savage", ValrathSavage), + ("vermling-scout", VermlingScout), + ("vermling-shaman", VermlingShaman), + ("living-bones", LivingBones), + ("living-corpse", LivingCorpse), + ("living-spirit", LivingSpirit), + ("cultist", Cultist), + ("flame-demon", FlameDemon), + ("frost-demon", FrostDemon), + ("earth-demon", EarthDemon), + ("wind-demon", WindDemon), + ("night-demon", NightDemon), + ("sun-demon", SunDemon), + ("ooze", Ooze), + ("giant-viper", GiantViper), + ("forest-imp", ForestImp), + ("hound", Hound), + ("cave-bear", CaveBear), + ("stone-golem", StoneGolem), + ("ancient-artillery", AncientArtillery), + ("rending-drake", RendingDrake), + ("spitting-drake", SpittingDrake), + ("lurker", Lurker), + ("savvas-icestorm", SavvasIcestorm), + ("savvas-lavaflow", SavvaLavaflow), + ("harrower-infester", HarrowerInfester), + ("deep-terror", DeepTerror), + ("black-imp", BlackImp) + ) + + private val bossDict: Map[String, BossType] = + import BossType.* + Map( + ("bandit-commander", BanditCommander), + ("human-commander", HumanCommander), + ("valrath-commander", ValrathCommander), + ("merciless-overseer", MercilessOverseer), + ("inox-bodyguard", InoxBodyguard), + ("captain-of-the-guard", CaptainOfTheGuard), + ("jekserah", Jekserah), + ("prime-demon", PrimeDemon), + ("elder-drake", ElderDrake), + ("the-betrayer", TheBetrayer), + ("the-colorless", TheColorless), + ("the-sightless-eye", TheSightlessEye), + ("dark-rider", DarkRider), + ("winged-horror", WingedHorror), + ("the-gloom", TheGloom), + ("manifestation-of-corruption", ManifestationOfCorruption) + ) + + val getAllMonsters: Map[String, NormalMonsterType] = normalDict + + val getAllBosses: Map[String, BossType] = bossDict + + def stringToMonsterType(monster: String): Option[MonsterType] = + normalDict.get(monster.toLowerCase()) match + case Some(m) => + Option(MonsterType.Normal(m)) + + case None => + bossDict.get(monster.toLowerCase()).map(v => MonsterType.Boss(v)) + + def monsterTypeToString(monster: MonsterType): Option[String] = + monster match + case MonsterType.Normal(m) => + normalDict.toList.filter(_ == m).headOption.map(_._1) + + case MonsterType.Boss(b) => + bossDict.toList.filter(_ == b).headOption.map(_._1) + + def getMonsterBucketSize(monster: MonsterType): Int = + monster match + case MonsterType.Boss(b) => + b match + case BossType.InoxBodyguard => 2 + case _ => 1 + + case MonsterType.Normal(t) => + import NormalMonsterType.* + t match + case AestherAshblade => 4 + case AestherScout => 4 + case BanditGuard => 6 + case BanditArcher => 6 + case CityGuard => 6 + case CityArcher => 6 + case InoxGuard => 6 + case InoxArcher => 6 + case InoxShaman => 4 + case ValrathTracker => 6 + case ValrathSavage => 6 + case VermlingScout => 10 + case VermlingShaman => 6 + case LivingBones => 10 + case LivingCorpse => 6 + case LivingSpirit => 6 + case Cultist => 6 + case FlameDemon => 6 + case FrostDemon => 6 + case EarthDemon => 6 + case WindDemon => 6 + case NightDemon => 6 + case SunDemon => 6 + case Ooze => 10 + case GiantViper => 10 + case ForestImp => 10 + case Hound => 6 + case CaveBear => 4 + case StoneGolem => 6 + case AncientArtillery => 6 + case RendingDrake => 6 + case SpittingDrake => 6 + case Lurker => 6 + case SavvasIcestorm => 4 + case SavvaLavaflow => 4 + case HarrowerInfester => 4 + case DeepTerror => 10 + case BlackImp => 10 + +enum MonsterType: + case Normal(normalType: NormalMonsterType) + case Boss(bossType: BossType) + +enum MonsterLevel: + case None + case Normal + case Elite + +enum NormalMonsterType: + case AestherAshblade + case AestherScout + case BanditGuard + case BanditArcher + case CityGuard + case CityArcher + case InoxGuard + case InoxArcher + case InoxShaman + case ValrathTracker + case ValrathSavage + case VermlingScout + case VermlingShaman + case LivingBones + case LivingCorpse + case LivingSpirit + case Cultist + case FlameDemon + case FrostDemon + case EarthDemon + case WindDemon + case NightDemon + case SunDemon + case Ooze + case GiantViper + case ForestImp + case Hound + case CaveBear + case StoneGolem + case AncientArtillery + case RendingDrake + case SpittingDrake + case Lurker + case SavvasIcestorm + case SavvaLavaflow + case HarrowerInfester + case DeepTerror + case BlackImp + +enum BossType: + case BanditCommander + case HumanCommander + case ValrathCommander + case MercilessOverseer + case InoxBodyguard + case CaptainOfTheGuard + case Jekserah + case PrimeDemon + case ElderDrake + case TheBetrayer + case TheColorless + case TheSightlessEye + case DarkRider + case WingedHorror + case TheGloom + case ManifestationOfCorruption + +final case class Monster(monster: MonsterType, id: Int, level: MonsterLevel, wasSummoned: Boolean, outOfPhase: Boolean) From 6e5f5e81f9ea65964e708a6f0454be779435e7c0 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 21:31:16 +0100 Subject: [PATCH 13/60] HexagonTests ported (failing) --- ui/ui/test/src/vgb/HexagonTests.scala | 89 +++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 ui/ui/test/src/vgb/HexagonTests.scala diff --git a/ui/ui/test/src/vgb/HexagonTests.scala b/ui/ui/test/src/vgb/HexagonTests.scala new file mode 100644 index 00000000..668ec129 --- /dev/null +++ b/ui/ui/test/src/vgb/HexagonTests.scala @@ -0,0 +1,89 @@ +package vgb + +class HexagonTests extends munit.FunSuite { + + test("should rotate (0, 2) 0 turn around 0, 0") { + assertEquals( + (0, 2), + Hexagon.rotate((0, 2), (0, 0), 0) + ) + } + + test("should rotate (0, 2) 1 turn around 0, 0") { + assertEquals( + (-2, 1), + Hexagon.rotate((0, 2), (0, 0), 1) + ) + } + + test("should rotate (-1, 0) 1 turns around 0, 0") { + assertEquals( + (-1, -1), + Hexagon.rotate((-1, 0), (0, 0), 1) + ) + } + + test("should rotate (0, 1) 6 turns around 0, 0") { + assertEquals( + (0, 1), + Hexagon.rotate((0, 1), (0, 0), 6) + ) + } + + test("should rotate (0, 1) 5 turns around 0, 0") { + assertEquals( + (1, 0), + Hexagon.rotate((0, 1), (0, 0), 5) + ) + } + + test("should rotate (0, 1) 4 turns around 0, 0") { + assertEquals( + (0, -1), + Hexagon.rotate((0, 1), (0, 0), 4) + ) + } + + test("should rotate (0, 1) 3 turns around 0, 0") { + assertEquals( + (-1, -1), + Hexagon.rotate((0, 1), (0, 0), 3) + ) + } + + test("should rotate (0, 1) 2 turns around 0, 0") { + assertEquals( + (-1, 0), + Hexagon.rotate((0, 1), (0, 0), 2) + ) + } + + test("should rotate (0, 1) 1 turn around 0, 0") { + assertEquals( + (-1, 1), + Hexagon.rotate((0, 1), (0, 0), 1) + ) + } + + test("should rotate (0, 2) 1 turn around 0, 3") { + assertEquals( + (1, 2), + Hexagon.rotate((0, 2), (0, 3), 1) + ) + } + + test("should rotate (0, 2) 3 turns around 0, 3") { + assertEquals( + (1, 4), + Hexagon.rotate((0, 2), (0, 3), 3) + ) + } + + test("should rotate (-1, 6) 1 turn around 0, 6") { + assertEquals( + (-1, 5), + Hexagon.rotate((-1, 6), (0, 6), 1) + ) + + } +} From 47be22c101d4f703a491773581a13981f93f1e8b Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sat, 8 Apr 2023 21:48:17 +0100 Subject: [PATCH 14/60] Ported Character class --- ui/ui/src/vgb/Character.scala | 145 ++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 ui/ui/src/vgb/Character.scala diff --git a/ui/ui/src/vgb/Character.scala b/ui/ui/src/vgb/Character.scala new file mode 100644 index 00000000..997464f5 --- /dev/null +++ b/ui/ui/src/vgb/Character.scala @@ -0,0 +1,145 @@ +package vgb + +object Character { + + val characterDictionary: Map[String, CharacterClass] = + import CharacterClass.* + Map( + ("brute", Brute), + ("tinkerer", Tinkerer), + ("scoundrel", Scoundrel), + ("cragheart", Cragheart), + ("mindthief", Mindthief), + ("spellweaver", Spellweaver), + ("diviner", Diviner), + + // Unlockable Characters + ("phoenix-face", BeastTyrant), + ("lightning-bolt", Berserker), + ("angry-face", Doomstalker), + ("triforce", Elementalist), + ("eclipse", Nightshroud), + ("cthulhu", PlagueHerald), + ("three-spears", Quartermaster), + ("saw", Sawbones), + ("music-note", Soothsinger), + ("concentric-circles", Summoner), + ("sun", Sunkeeper), + ("envelope-x", Bladeswarm) + ) + + val soloScenarioDict: Map[String, (Int, String)] = + Map( + ("brute", (1, "Return to Black Barrow")), + ("tinkerer", (2, "An Unfortunate Intrusion")), + ("scoundrel", (4, "Armory Heist")), + ("cragheart", (5, "Stone Defense")), + ("mindthief", (6, "Rodent Liberation")), + ("spellweaver", (3, "Corrupted Laboratory")), + ("diviner", (18, "Forecast of the Inevitable")), + + // -- Unlockable Characters + ("phoenix-face", (17, "The Caged Bear")), + ("lightning-bolt", (8, "Unnatural Insults")), + ("angry-face", (14, "Corrupted Hunt")), + ("triforce", (16, "Elemental Secrets")), + ("eclipse", (11, "Harvesting the Night")), + ("cthulhu", (12, "Plagued Crypt")), + ("three-spears", (9, "Storage Fees")), + ("saw", (15, "Aftermath")), + ("music-note", (13, "Battle of the Bards")), + ("concentric-circles", (10, "Plane of Wild Beasts")), + ("sun", (7, "Caravan Escort")) + ) + + def characterToString(character: CharacterClass): Option[String] = + characterDictionary.find(_._2 == character).map(_._1) + + def stringToCharacter(character: String): Option[CharacterClass] = + characterDictionary.get(character.toLowerCase) + + def getRealCharacterName(character: CharacterClass): String = + import CharacterClass.* + character match + case BeastTyrant => + "Beast Tyrant" + + case Berserker => + "Berserker" + + case Bladeswarm => + "Bladeswarm" + + case Brute => + "Brute" + + case Cragheart => + "Cragheart" + + case Diviner => + "Diviner" + + case Doomstalker => + "Doomstalker" + + case Elementalist => + "Elementalist" + + case Mindthief => + "Mindthief" + + case Nightshroud => + "Nightshroud" + + case PlagueHerald => + "Plague Herald" + + case Quartermaster => + "Quartermaster" + + case Sawbones => + "Sawbones" + + case Scoundrel => + "Scoundrel" + + case Soothsinger => + "Soothsinger" + + case Spellweaver => + "Spellweaver" + + case Summoner => + "Summoner" + + case Sunkeeper => + "Sunkeeper" + + case Tinkerer => + "Tinkerer" + + def getSoloScenarios: Map[String, (Int, String)] = + soloScenarioDict + +} + +enum CharacterClass: + case BeastTyrant + case Berserker + case Bladeswarm + case Brute + case Cragheart + case Diviner + case Doomstalker + case Elementalist + case Mindthief + case Nightshroud + case PlagueHerald + case Quartermaster + case Sawbones + case Scoundrel + case Soothsinger + case Spellweaver + case Summoner + case Sunkeeper + case Tinkerer From 2a8bf5debbe25dd87e25f791d17c16d2ffaaefb8 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sun, 9 Apr 2023 09:22:39 +0100 Subject: [PATCH 15/60] Ported SpecialRules class --- ui/ui/src/vgb/SpecialRules.scala | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 ui/ui/src/vgb/SpecialRules.scala diff --git a/ui/ui/src/vgb/SpecialRules.scala b/ui/ui/src/vgb/SpecialRules.scala new file mode 100644 index 00000000..a40d89a0 --- /dev/null +++ b/ui/ui/src/vgb/SpecialRules.scala @@ -0,0 +1,37 @@ +package vgb + +import BoardOverlayType.Door +import DoorSubType.DarkFog + +object SpecialRules: + + def scenario101DoorUpdate(state: GameState): GameState = + (removeJ1bbFog andThen removeJ1bFog)(state) + + def removeJ1bbFog(state: GameState): GameState = + val shouldRemove = + state.visibleRooms.exists(_ == MapTileRef.J1ba) && + state.visibleRooms.exists(_ == MapTileRef.J1bb) + + if shouldRemove then state.copy(overlays = removeFog(List((9, 10), (8, 9), (8, 8)), state.overlays)) + else state + + def removeJ1bFog(state: GameState): GameState = + val shouldRemove = + state.visibleRooms.exists(_ == MapTileRef.J1ba) && + state.visibleRooms.exists(_ == MapTileRef.J1b) + + if shouldRemove then state.copy(overlays = removeFog(List((4, 11), (5, 10), (4, 9)), state.overlays)) + else state + + def removeFog(cells: List[(Int, Int)], overlays: List[BoardOverlay]): List[BoardOverlay] = + overlays.flatMap { o => + if cells.exists(c => o.cells.exists(_ == c)) then + o.ref match + case Door(DarkFog, _) => + None + + case _ => + Option(o) + else Option(o) + } From a826b0f4588141c29c8bcfc455f7307162b2ff28 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sun, 9 Apr 2023 09:45:31 +0100 Subject: [PATCH 16/60] WIP --- ui/ui/src/vgb/BoardOverlay.scala | 440 ++++++++++++++ ui/ui/src/vgb/Game.scala | 972 +++++++++++++++++++++++++++++++ ui/ui/src/vgb/Scenario.scala | 187 ++++++ 3 files changed, 1599 insertions(+) create mode 100644 ui/ui/src/vgb/BoardOverlay.scala create mode 100644 ui/ui/src/vgb/Game.scala create mode 100644 ui/ui/src/vgb/Scenario.scala diff --git a/ui/ui/src/vgb/BoardOverlay.scala b/ui/ui/src/vgb/BoardOverlay.scala new file mode 100644 index 00000000..6267b994 --- /dev/null +++ b/ui/ui/src/vgb/BoardOverlay.scala @@ -0,0 +1,440 @@ +package vgb + +object BoardOverlay: + + val overlayDictionary: Map[String, BoardOverlayType] = { + import BoardOverlayType.* + import DoorSubType.* + import CorridorSize.* + import CorridorMaterial.* + import DifficultTerrainSubType.* + import WallSubType.* + import ObstacleSubType.* + import HazardSubType.* + import TreasureSubType.* + import ChestType.* + import TrapSubType.* + Map( + "door-altar" -> Door(AltarDoor, Nil), + "door-stone" -> Door(Stone, Nil), + "door-wooden" -> Door(Wooden, Nil), + "door-dark-fog" -> Door(DarkFog, Nil), + "door-light-fog" -> Door(LightFog, Nil), + "door-breakable-wall" -> Door(BreakableWall, Nil), + "corridor-dark-1" -> Door((Corridor(Dark, One)), Nil), + "corridor-earth-1" -> Door((Corridor(Earth, One)), Nil), + "corridor-manmade-stone-1" -> Door((Corridor(ManmadeStone, One)), Nil), + "corridor-natural-stone-1" -> Door((Corridor(NaturalStone, One)), Nil), + "corridor-pressure-plate-1" -> Door((Corridor(PressurePlate, One)), Nil), + "corridor-wood-1" -> Door((Corridor(Wood, One)), Nil), + "corridor-dark-2" -> Door((Corridor(Dark, Two)), Nil), + "corridor-earth-2" -> Door((Corridor(Earth, Two)), Nil), + "corridor-manmade-stone-2" -> Door((Corridor(ManmadeStone, Two)), Nil), + "corridor-natural-stone-2" -> Door((Corridor(NaturalStone, Two)), Nil), + "corridor-wood-2" -> Door((Corridor(Wood, Two)), Nil), + "difficult-terrain-log" -> DifficultTerrain(Log), + "difficult-terrain-rubble" -> DifficultTerrain(Rubble), + "difficult-terrain-stairs" -> DifficultTerrain(Stairs), + "difficult-terrain-stairs-vert" -> DifficultTerrain(VerticalStairs), + "difficult-terrain-water" -> DifficultTerrain(Water), + "hazard-hot-coals" -> Hazard(HotCoals), + "hazard-thorns" -> Hazard(Thorns), + "obstacle-altar" -> Obstacle(Altar), + "obstacle-barrel" -> Obstacle(Barrel), + "obstacle-bookcase" -> Obstacle(Bookcase), + "obstacle-boulder-1" -> Obstacle(Boulder1), + "obstacle-boulder-2" -> Obstacle(Boulder2), + "obstacle-boulder-3" -> Obstacle(Boulder3), + "obstacle-bush" -> Obstacle(Bush), + "obstacle-cabinet" -> Obstacle(Cabinet), + "obstacle-crate" -> Obstacle(Crate), + "obstacle-crystal" -> Obstacle(Crystal), + "obstacle-dark-pit" -> Obstacle(DarkPit), + "obstacle-fountain" -> Obstacle(Fountain), + "obstacle-mirror" -> Obstacle(Mirror), + "obstacle-nest" -> Obstacle(Nest), + "obstacle-pillar" -> Obstacle(Pillar), + "obstacle-rock-column" -> Obstacle(RockColumn), + "obstacle-sarcophagus" -> Obstacle(Sarcophagus), + "obstacle-shelf" -> Obstacle(Shelf), + "obstacle-stalagmites" -> Obstacle(Stalagmites), + "obstacle-stump" -> Obstacle(Stump), + "obstacle-table" -> Obstacle(Table), + "obstacle-totem" -> Obstacle(Totem), + "obstacle-tree-3" -> Obstacle(Tree3), + "obstacle-wall-section" -> Obstacle(WallSection), + "rift" -> Rift, + "starting-location" -> StartingLocation, + "token-a" -> Token("a"), + "token-b" -> Token("b"), + "token-c" -> Token("c"), + "token-d" -> Token("d"), + "token-e" -> Token("e"), + "token-f" -> Token("f"), + "token-1" -> Token("1"), + "token-2" -> Token("2"), + "token-3" -> Token("3"), + "token-4" -> Token("4"), + "token-5" -> Token("5"), + "token-6" -> Token("6"), + "trap-bear" -> Trap(BearTrap), + "trap-spike" -> Trap(Spike), + "trap-poison" -> Trap(Poison), + "treasure-chest" -> Treasure(Chest(Locked)), + "treasure-coin" -> Treasure(Coin(1)), + "wall-huge-rock" -> Wall(HugeRock), + "wall-iron" -> Wall(Iron), + "wall-large-rock" -> Wall(LargeRock), + "wall-obsidian-glass" -> Wall(ObsidianGlass), + "wall-rock" -> Wall(Rock) + ) + } + +// getBoardOverlayName : BoardOverlayType -> Maybe String +// getBoardOverlayName overlay = +// let +// compare = +// case overlay of +// Door d _ -> +// Door d , Nil + +// Treasure t -> +// case t of +// Chest _ -> +// Treasure (Chest Locked) + +// Coin _ -> +// Treasure (Coin 1) + +// _ -> +// overlay +// in +// overlayDictionary +// |> Dict.filter (\_ v -> v == compare) +// |> Dict.keys +// |> List.head + +// def getBoardOverlayType(overlayName: String): Option[BoardOverlayType] = +// overlayDictionary.get(overlayName) + +// def getAllOverlayTypes: List[BoardOverlayType] = +// overlayDictionary.values.toList + +// def getOverlayTypesWithLabel: Map[String, BoardOverlayType] = +// overlayDictionary + +// getOverlayLabel : BoardOverlayType -> String +// getOverlayLabel overlay = +// case overlay of +// Door d _ -> +// case d of +// AltarDoor -> +// "Altar" + +// Stone -> +// "Stone Door" + +// Wooden -> +// "Wooden Door" + +// BreakableWall -> +// "Breakable Wall" + +// Corridor c _ -> +// case c of +// Dark -> +// "Dark Corridor" + +// Earth -> +// "Earth Corridor" + +// ManmadeStone -> +// "Manmade Stone Corridor" + +// NaturalStone -> +// "Natural Stone Corridor" + +// PressurePlate -> +// "Pressure Plate" + +// Wood -> +// "Wooden Corridor" + +// DarkFog -> +// "Dark Fog" + +// LightFog -> +// "Light Fog" + +// DifficultTerrain d -> +// case d of +// Log -> +// "Fallen Log" + +// Rubble -> +// "Rubble" + +// Stairs -> +// "Stairs" + +// VerticalStairs -> +// "Stairs" + +// Water -> +// "Water" + +// Hazard h -> +// case h of +// HotCoals -> +// "Hot Coals" + +// Thorns -> +// "Thorns" + +// Highlight c -> +// Colour.toString c ++ " Highlight" + +// Obstacle o -> +// case o of +// Altar -> +// "Altar" + +// Barrel -> +// "Barrel" + +// Bookcase -> +// "Bookcase" + +// Boulder1 -> +// "Boulder" + +// Boulder2 -> +// "Boulder" + +// Boulder3 -> +// "Boulder" + +// Bush -> +// "Bush" + +// Cabinet -> +// "Cabinet" + +// Crate -> +// "Crate" + +// Crystal -> +// "Crystal" + +// DarkPit -> +// "Dark Pit" + +// Fountain -> +// "Fountain" + +// Mirror -> +// "Mirror" + +// Nest -> +// "Nest" + +// Pillar -> +// "Pillar" + +// RockColumn -> +// "Rock Column" + +// Sarcophagus -> +// "Sarcophagus" + +// Shelf -> +// "Sheelves" + +// Stalagmites -> +// "Stalagmites" + +// Stump -> +// "Tree Stump" + +// Table -> +// "Table" + +// Totem -> +// "Totem" + +// Tree3 -> +// "Tree" + +// WallSection -> +// "Wall" + +// Rift -> +// "Rift" + +// StartingLocation -> +// "Starting Location" + +// Trap t -> +// case t of +// BearTrap -> +// "Bear Trap" + +// Spike -> +// "Spike Trap" + +// Poison -> +// "Poison Trap" + +// Treasure t -> +// case t of +// Chest c -> +// "Treasure Chest " +// ++ (case c of +// Goal -> +// "Goal" + +// Locked -> +// "(locked)" + +// NormalChest i -> +// String.fromInt i +// ) + +// Coin i -> +// String.fromInt i +// ++ (case i of +// 1 -> +// " Coin" + +// _ -> +// " Coins" +// ) + +// Token t -> +// "Token (" ++ t ++ ")" + +// Wall w -> +// case w of +// HugeRock -> +// "Huge Rock Wall" + +// Iron -> +// "Iron Wall" + +// LargeRock -> +// "Large Rock Wall" + +// ObsidianGlass -> +// "Obsidian Glass Wall" + +// Rock -> +// "Rock Wall" + +enum BoardOverlayType: + case DifficultTerrain(typ: DifficultTerrainSubType) + case Door(typ: DoorSubType, tiles: List[MapTileRef]) + case Hazard(typ: HazardSubType) + case Highlight(colour: Colour) + case Obstacle(typ: ObstacleSubType) + case Rift + case StartingLocation + case Trap(typ: TrapSubType) + case Treasure(typ: TreasureSubType) + case Token(value: String) + case Wall(typ: WallSubType) + +enum DoorSubType: + case AltarDoor + case BreakableWall + case Corridor(material: CorridorMaterial, size: CorridorSize) + case DarkFog + case LightFog + case Stone + case Wooden + +enum CorridorMaterial: + case Dark + case Earth + case ManmadeStone + case NaturalStone + case PressurePlate + case Wood + +enum CorridorSize: + case One + case Two + +enum TrapSubType: + case BearTrap + case Poison + case Spike + +enum HazardSubType: + case HotCoals + case Thorns + +enum DifficultTerrainSubType: + case Log + case Rubble + case Stairs + case VerticalStairs + case Water + +enum ObstacleSubType: + case Altar + case Barrel + case Bookcase + case Boulder1 + case Boulder2 + case Boulder3 + case Bush + case Cabinet + case Crate + case Crystal + case DarkPit + case Fountain + case Mirror + case Nest + case Pillar + case RockColumn + case Sarcophagus + case Shelf + case Stalagmites + case Stump + case Table + case Totem + case Tree3 + case WallSection + +enum TreasureSubType: + case Chest(typ: ChestType) + case Coin(value: Int) + +enum ChestType: + case NormalChest(i: Int) + case Goal + case Locked + +enum WallSubType: + case HugeRock + case Iron + case LargeRock + case ObsidianGlass + case Rock + +enum BoardOverlayDirectionType: + case Default + case Horizontal + case Vertical + case VerticalReverse + case DiagonalLeft + case DiagonalRight + case DiagonalLeftReverse + case DiagonalRightReverse + +final case class BoardOverlay( + ref: BoardOverlayType, + id: Int, + direction: BoardOverlayDirectionType, + cells: List[(Int, Int)] +) diff --git a/ui/ui/src/vgb/Game.scala b/ui/ui/src/vgb/Game.scala new file mode 100644 index 00000000..11c678c0 --- /dev/null +++ b/ui/ui/src/vgb/Game.scala @@ -0,0 +1,972 @@ +package vgb + +// object Game: + + // empty : Game + // empty = + // Game emptyState Scenario.empty (Random.initialSeed 0) [] Array.empty + + + // emptyState : GameState + // emptyState = + // GameState (InbuiltScenario Gloomhaven 1) [] 0 [] [] [] Dict.empty "" + + + // getPieceType : PieceType -> String + // getPieceType piece = + // case piece of + // Player _ -> + // "player" + + // AI t -> + // case t of + // Summons _ -> + // "player" + + // Enemy _ -> + // "monster" + + // None -> + // "" + + + // getPieceName : PieceType -> String + // getPieceName piece = + // case piece of + // Player p -> + // Maybe.withDefault "" (characterToString p) + + // AI t -> + // case t of + // Summons _ -> + // "summons" + + // Enemy e -> + // Maybe.withDefault "" (monsterTypeToString e.monster) + + // None -> + // "" + + + // generateGameMap : GameStateScenario -> Scenario -> String -> List CharacterClass -> Seed -> Game + // generateGameMap gameStateScenario scenario roomCode players seed = + // let + // ( mapTiles, bounds ) = + // mapTileDataToList scenario.mapTilesData Nothing + + // availableMonsters = + // map (\m -> ( Maybe.withDefault "" (monsterTypeToString m), initialize (getMonsterBucketSize m) identity )) scenario.additionalMonsters + // |> filter (\( k, _ ) -> k /= "") + // |> map (\( k, v ) -> ( k, Tuple.first (orderRandomArrElement Array.empty seed v) )) + // |> Dict.fromList + + // initGameState = + // GameState gameStateScenario + // players + // 0 + // [] + // [] + // [] + // availableMonsters + // roomCode + + // initOverlays = + // mapTileDataToOverlayList scenario.mapTilesData + + // {- Build a square array capable of holding the whole map + // We add 2 to account for the zero index, and also row drift if the original started on a non-even row + // -} + // arrSize = + // max (abs (bounds.maxX - bounds.minX)) (abs (bounds.maxY - bounds.minY)) + // + 1 + // + (if Bitwise.and bounds.minY 1 == 1 then + // 1 + + // else + // 0 + // ) + + // -- The Y offset needs adjusting if the start of the original array was an odd row + // offsetY = + // if Bitwise.and bounds.minY 1 == 1 then + // bounds.minY - 1 + + // else + // bounds.minY + + // initMap = + // initialize arrSize (always (initialize arrSize (always (Cell [] False)))) + + // initGame = + // setCellsFromMapTiles mapTiles initOverlays bounds.minX offsetY seed (Game initGameState scenario seed [] initMap) + // |> ensureUniqueOverlays + + // startRooms = + // filterMap + // (\o -> + // case o.ref of + // StartingLocation -> + // Just o.cells + + // _ -> + // Nothing + // ) + // initGame.state.overlays + // |> List.foldl (++) [] + // |> filterMap (getRoomsByCoord initGame.staticBoard) + // |> List.foldl (++) [] + // |> uniqueBy (\ref -> Maybe.withDefault "" (refToString ref)) + // in + // revealRooms initGame startRooms + + + // setCellsFromMapTiles : List MapTile -> Dict String ( List BoardOverlay, List ScenarioMonster ) -> Int -> Int -> Seed -> Game -> Game + // setCellsFromMapTiles mapTileList overlays offsetX offsetY seed game = + // case mapTileList of + // head :: rest -> + // let + // ( newGame, newSeed ) = + // setCellFromMapTile game overlays offsetX offsetY head seed + // in + // setCellsFromMapTiles rest overlays offsetX offsetY newSeed newGame + + // _ -> + // game + + + // setCellFromMapTile : Game -> Dict String ( List BoardOverlay, List ScenarioMonster ) -> Int -> Int -> MapTile -> Seed -> ( Game, Seed ) + // setCellFromMapTile game overlays offsetX offsetY tile seed = + // let + // x = + // tile.x - offsetX + + // y = + // tile.y - offsetY + + // refString = + // Maybe.withDefault "" (refToString tile.ref) + + // ( isOrigin, newOrigins ) = + // if tile.originalX == 0 && tile.originalY == 0 then + // ( True, RoomData tile.ref ( x, y ) tile.turns :: game.roomData ) + + // else + // ( False, game.roomData ) + + // state = + // game.state + + // ( boardOverlays, piece ) = + // case Dict.get refString overlays of + // Just ( o, m ) -> + // ( filter (filterByCoord tile.originalX tile.originalY) o + // |> map (mapOverlayCoord tile.originalX tile.originalY x y tile.turns) + // , filter (filterMonsterLevel (List.length game.state.players)) m + // |> filter (\f -> f.initialX == tile.originalX && f.initialY == tile.originalY) + // |> head + // |> getPieceFromMonster (List.length game.state.players) + // |> mapPieceCoord tile.originalX tile.originalY x y + // ) + + // Nothing -> + // ( [], Piece None 0 0 ) + + // doorRefs = + // boardOverlays + // |> filterMap + // (\o -> + // case o.ref of + // Door _ refs -> + // Just refs + + // _ -> + // Nothing + // ) + // |> foldl (++) [] + + // ( monsterBucket, newSeed ) = + // case piece.ref of + // AI (Enemy m) -> + // initialize (getMonsterBucketSize m.monster) identity + // |> orderRandomArrElement Array.empty seed + // |> (\( a, s ) -> ( Just ( Maybe.withDefault "" (monsterTypeToString m.monster), a ), s )) + + // _ -> + // ( Nothing, seed ) + + // newGameState = + // { state + // | overlays = game.state.overlays ++ boardOverlays + // , pieces = + // game.state.pieces + // ++ (case piece.ref of + // None -> + // [] + + // _ -> + // [ piece ] + // ) + // , availableMonsters = + // case monsterBucket of + // Just b -> + // b + // :: Dict.toList game.state.availableMonsters + // |> filter (\( k, _ ) -> k /= "") + // |> Dict.fromList + + // _ -> + // game.state.availableMonsters + // } + + // rowArr = + // Array.get y game.staticBoard + + // newBoard = + // case rowArr of + // Just yRow -> + // let + // cell = + // Array.get x yRow + // in + // case cell of + // Just foundCell -> + // let + // newCell = + // { foundCell + // | passable = + // if foundCell.passable == False then + // tile.passable + + // else + // True + // , rooms = + // tile.ref + // :: (doorRefs ++ foundCell.rooms) + // |> uniqueBy (\r -> Maybe.withDefault "" (refToString r)) + // } + // in + // set y (set x newCell yRow) game.staticBoard + + // Nothing -> + // game.staticBoard + + // Nothing -> + // game.staticBoard + // in + // if tile.passable || (List.length doorRefs > 0) || isOrigin then + // ( { game | state = newGameState, staticBoard = newBoard, roomData = newOrigins } + // , newSeed + // ) + + // else + // ( { game | seed = newSeed }, newSeed ) + + + // filterMonsterLevel : Int -> ScenarioMonster -> Bool + // filterMonsterLevel numPlayers monster = + // if numPlayers < 3 then + // monster.twoPlayer /= Monster.None + + // else if numPlayers < 4 then + // monster.threePlayer /= Monster.None + + // else + // monster.fourPlayer /= Monster.None + + + // getLevelForMonster : Int -> ScenarioMonster -> MonsterLevel + // getLevelForMonster numPlayers monster = + // if numPlayers < 3 then + // monster.twoPlayer + + // else if numPlayers < 4 then + // monster.threePlayer + + // else + // monster.fourPlayer + + + // getPieceFromMonster : Int -> Maybe ScenarioMonster -> Piece + // getPieceFromMonster numPlayers monster = + // case monster of + // Just p -> + // let + // m = + // p.monster + + // level = + // getLevelForMonster numPlayers p + // in + // if level == Monster.None then + // Piece None 0 0 + + // else + // Piece (AI (Enemy { m | level = level })) p.initialX p.initialY + + // Nothing -> + // Piece None 0 0 + + + // getRoomsByCoord : Array (Array Cell) -> ( Int, Int ) -> Maybe (List MapTileRef) + // getRoomsByCoord cells ( x, y ) = + // Array.get y cells + // |> Maybe.andThen + // (\colCell -> + // Array.get x colCell + // |> Maybe.map (\cell -> cell.rooms) + // ) + + + // filterByCoord : Int -> Int -> BoardOverlay -> Bool + // filterByCoord x y overlay = + // case overlay.cells of + // ( overlayX, overlayY ) :: _ -> + // overlayX == x && overlayY == y + + // [] -> + // False + + + // mapPieceCoord : Int -> Int -> Int -> Int -> Piece -> Piece + // mapPieceCoord _ _ newX newY piece = + // { piece | x = newX, y = newY } + + + // mapOverlayCoord : Int -> Int -> Int -> Int -> Int -> BoardOverlay -> BoardOverlay + // mapOverlayCoord originalX originalY newX newY turns overlay = + // let + // ( oX, oY, oZ ) = + // oddRowToCube ( originalX, originalY ) + + // ( nX, nY, nZ ) = + // oddRowToCube ( newX, newY ) + + // diffX = + // nX - oX + + // diffY = + // nY - oY + + // diffZ = + // nZ - oZ + // in + // { overlay + // | cells = + // map + // (\c -> + // let + // ( x1, y1, z1 ) = + // Hexagon.rotate c ( originalX, originalY ) turns + // |> oddRowToCube + // in + // cubeToOddRow ( diffX + x1, diffY + y1, diffZ + z1 ) + // ) + // overlay.cells + // } + + + // movePiece : Piece -> Maybe ( Int, Int ) -> ( Int, Int ) -> Game -> ( Game, Piece ) + // movePiece piece fromCoords ( toX, toY ) game = + // let + // gamestate = + // game.state + + // ( newPieces, newPiece ) = + // movePieceWithoutState piece fromCoords ( toX, toY ) game.state.pieces + + // newGamestate = + // case fromCoords of + // Just ( _, _ ) -> + // { gamestate | pieces = newPieces |> filter (\p -> p /= newPiece) } + + // Nothing -> + // gamestate + // in + // if canMoveTo ( toX, toY ) { game | state = newGamestate } True then + // ( { game | state = { newGamestate | pieces = newPiece :: newGamestate.pieces } } + // , newPiece + // ) + + // else + // ( game, piece ) + + + // movePieceWithoutState : Piece -> Maybe ( Int, Int ) -> ( Int, Int ) -> List Piece -> ( List Piece, Piece ) + // movePieceWithoutState piece fromCoords ( toX, toY ) pieces = + // let + // newPiece = + // { piece | x = toX, y = toY } + + // newPieces = + // case fromCoords of + // Just ( fromX, fromY ) -> + // filter (removePiece { piece | x = fromX, y = fromY }) pieces + + // Nothing -> + // pieces + // in + // if List.any (\p -> p.x == toX && p.y == toY) newPieces then + // ( pieces, piece ) + + // else + // ( newPiece :: newPieces, newPiece ) + + + // moveOverlay : BoardOverlay -> Maybe ( Int, Int ) -> Maybe ( Int, Int ) -> ( Int, Int ) -> Game -> ( Game, BoardOverlay, Maybe ( Int, Int ) ) + // moveOverlay overlay fromCoords prevCoords ( toX, toY ) game = + // let + // gamestate = + // game.state + + // ( newOverlays, newOverlay, _ ) = + // moveOverlayWithoutState overlay fromCoords prevCoords ( toX, toY ) game.state.overlays + + // newGamestate = + // case fromCoords of + // Just _ -> + // { gamestate + // | overlays = + // newOverlays + // |> filter (\o -> o /= newOverlay) + // } + + // Nothing -> + // gamestate + + // newGame = + // { game | state = newGamestate } + // in + // if all (\c -> canMoveTo c newGame True) newOverlay.cells then + // ( { game | state = { newGamestate | overlays = newOverlay :: newGamestate.overlays } } + // , newOverlay + // , Just ( toX, toY ) + // ) + + // else + // ( game, overlay, prevCoords ) + + + // moveOverlayWithoutState : BoardOverlay -> Maybe ( Int, Int ) -> Maybe ( Int, Int ) -> ( Int, Int ) -> List BoardOverlay -> ( List BoardOverlay, BoardOverlay, Maybe ( Int, Int ) ) + // moveOverlayWithoutState overlay fromCoords prevCoords ( toX, toY ) overlays = + // let + // ( fromX, fromY, fromZ ) = + // case fromCoords of + // Just ( oX, oY ) -> + // oddRowToCube ( oX, oY ) + + // Nothing -> + // ( 0, 0, 0 ) + + // ( prevDiffX, prevDiffY, prevDiffZ ) = + // case prevCoords of + // Just p -> + // let + // ( pX, pY, pZ ) = + // oddRowToCube p + // in + // ( fromX - pX, fromY - pY, fromZ - pZ ) + + // Nothing -> + // ( 0, 0, 0 ) + + // ( diffX, diffY, diffZ ) = + // let + // ( dX, dY, dZ ) = + // case fromCoords of + // Just _ -> + // let + // ( newX, newY, newZ ) = + // oddRowToCube ( toX, toY ) + // in + // ( newX - fromX, newY - fromY, newZ - fromZ ) + + // Nothing -> + // oddRowToCube ( toX, toY ) + // in + // ( dX + prevDiffX, dY + prevDiffY, dZ + prevDiffZ ) + + // moveCells c = + // let + // ( cX, cY, cZ ) = + // oddRowToCube c + // in + // cubeToOddRow ( cX + diffX, cY + diffY, cZ + diffZ ) + + // newOverlay = + // { overlay | cells = map moveCells overlay.cells } + + // newOverlays = + // case fromCoords of + // Just _ -> + // filter + // (\o -> o.id /= overlay.id) + // overlays + + // Nothing -> + // overlays + // in + // ( newOverlays + // , newOverlay + // , Just ( toX, toY ) + // ) + + + // revealRooms : Game -> List MapTileRef -> Game + // revealRooms game rooms = + // case rooms of + // room :: rest -> + // revealRooms (revealRoom room game) rest + + // _ -> + // game + + + // revealRoom : MapTileRef -> Game -> Game + // revealRoom room game = + // if member room game.state.visibleRooms then + // game + + // else + // let + // roomCells = + // indexedMap (\y arr -> indexedMap (\x cell -> ( cell, ( x, y ) )) arr) game.staticBoard + // |> Array.foldl (\a b -> fromList (toList a ++ toList b)) Array.empty + // |> toList + // |> filter (\( cell, _ ) -> cell.passable && member room cell.rooms) + // |> map (\( _, c ) -> c) + + // ( assignedMonsters, availableMonsters ) = + // filterMap + // (\p -> + // case p.ref of + // AI (Enemy e) -> + // if member ( p.x, p.y ) roomCells && e.id == 0 then + // Just p + + // else + // Nothing + + // _ -> + // Nothing + // ) + // game.state.pieces + // |> assignIdentifiers game.state.availableMonsters [] + // |> (\( m, a ) -> + // ( filterMap + // (\p -> + // case p.ref of + // AI (Enemy e) -> + // if e.id /= 0 then + // Just p + + // else + // Nothing + + // _ -> + // Nothing + // ) + // m + // , a + // ) + // ) + + // ignoredPieces = + // filterMap + // (\p -> + // case p.ref of + // AI (Enemy e) -> + // if member ( p.x, p.y ) roomCells && e.id == 0 then + // Nothing + + // else + // Just p + + // _ -> + // Just p + // ) + // game.state.pieces + + // state = + // game.state + + // newGame = + // { game | state = { state | visibleRooms = room :: state.visibleRooms, availableMonsters = availableMonsters, pieces = ignoredPieces ++ assignedMonsters } } + + // corridors = + // game.state.overlays + // |> filter + // (\o -> + // case o.ref of + // Door (Corridor m _) refs -> + // case m of + // Dark -> + // False + + // _ -> + // member room refs + + // _ -> + // False + // ) + // |> filterMap + // (\o -> + // case o.ref of + // Door (Corridor _ _) refs -> + // Just refs + + // _ -> + // Nothing + // ) + // |> foldl (++) [] + // |> filter (\r -> r /= room) + // in + // revealRooms newGame corridors + + + // removePieceFromBoard : Piece -> Game -> Game + // removePieceFromBoard piece game = + // let + // gameState = + // game.state + + // filteredPieces = + // filter (removePiece piece) gameState.pieces + + // newAvailableMonsters = + // case piece.ref of + // AI (Enemy m) -> + // let + // ref = + // Maybe.withDefault "" (monsterTypeToString m.monster) + // in + // case Dict.get ref gameState.availableMonsters of + // Just v -> + // insert ref (push (m.id - 1) v) gameState.availableMonsters + + // Nothing -> + // insert ref (fromList [ m.id - 1 ]) gameState.availableMonsters + + // _ -> + // gameState.availableMonsters + + // newOverlays = + // case piece.ref of + // AI (Enemy m) -> + // if m.wasSummoned then + // gameState.overlays + + // else if + // any + // (\o -> + // case o.ref of + // Treasure (Coin _) -> + // member ( piece.x, piece.y ) o.cells + + // _ -> + // False + // ) + // gameState.overlays + // then + // map + // (\o -> + // case o.ref of + // Treasure (Coin i) -> + // if member ( piece.x, piece.y ) o.cells then + // { o | ref = Treasure (Coin (i + 1)) } + + // else + // o + + // _ -> + // o + // ) + // gameState.overlays + + // else + // let + // maxId = + // case + // List.map (\o -> o.id) gameState.overlays + // |> List.maximum + // of + // Just i -> + // i + + // Nothing -> + // 0 + // in + // BoardOverlay (Treasure (Coin 1)) (maxId + 1) Default [ ( piece.x, piece.y ) ] + // :: gameState.overlays + + // _ -> + // gameState.overlays + // in + // { game | state = { gameState | pieces = filteredPieces, overlays = newOverlays, availableMonsters = newAvailableMonsters } } + + + // assignIdentifiers : Dict String (Array Int) -> List Piece -> List Piece -> ( List Piece, Dict String (Array Int) ) + // assignIdentifiers availableMonsters processed monsters = + // case monsters of + // m :: rest -> + // let + // ( newM, newBucket ) = + // assignIdentifier availableMonsters m + // in + // assignIdentifiers newBucket (newM :: processed) rest + + // _ -> + // ( processed, availableMonsters ) + + + // assignIdentifier : Dict String (Array Int) -> Piece -> ( Piece, Dict String (Array Int) ) + // assignIdentifier availableMonsters p = + // case p.ref of + // AI (Enemy monster) -> + // case monsterTypeToString monster.monster of + // Just key -> + // case Dict.get key availableMonsters of + // Just bucket -> + // case Array.get 0 bucket of + // Just id -> + // ( { p | ref = AI (Enemy { monster | id = id + 1 }) }, insert key (slice 1 (length bucket) bucket) availableMonsters ) + + // Nothing -> + // ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) + + // Nothing -> + // ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) + + // Nothing -> + // ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) + + // _ -> + // ( p, availableMonsters ) + + + // removePiece : Piece -> Piece -> Bool + // removePiece pieceToRemove comparePiece = + // pieceToRemove.ref + // /= comparePiece.ref + + + // canMoveTo : ( Int, Int ) -> Game -> Bool -> Bool + // canMoveTo ( toX, toY ) game ignoreObstacles = + // let + // obstacleList = + // if ignoreObstacles then + // [] + + // else + // game.state.overlays + // |> filter + // (\o -> + // case o.ref of + // Obstacle _ -> + // True + + // Trap _ -> + // True + + // Door (Corridor _ _) _ -> + // False + + // Door _ _ -> + // True + + // _ -> + // False + // ) + // in + // case Array.get toY game.staticBoard of + // Just row -> + // case Array.get toX row of + // Just cell -> + // any (\c -> List.member c cell.rooms) game.state.visibleRooms + // && cell.passable + // && all (\p -> p.x /= toX || p.y /= toY) game.state.pieces + // && (ignoreObstacles + // || all (\o -> List.all (\c -> c /= ( toX, toY )) o.cells) obstacleList + // ) + + // Nothing -> + // False + + // Nothing -> + // False + + + // orderRandomArrElement : Array a -> Seed -> Array a -> ( Array a, Seed ) + // orderRandomArrElement bucket seed original = + // if length original == 0 then + // ( bucket, seed ) + + // else + // let + // ( index, newSeed ) = + // Random.step (Random.int 0 (length original - 1)) seed + + // slice1 = + // toList (slice 0 index original) + + // slice2 = + // toList (slice (index + 1) (length original) original) + // in + // case Array.get index original of + // Just o -> + // orderRandomArrElement (push o bucket) newSeed (fromList (slice1 ++ slice2)) + + // Nothing -> + // ( bucket, seed ) + + + // assignPlayers : List CharacterClass -> Game -> Game + // assignPlayers players game = + // let + // state = + // game.state + + // filteredPieces = + // filter + // (\p -> + // case p.ref of + // AI (Enemy _) -> + // True + + // _ -> + // False + // ) + // state.pieces + + // statingLocations = + // filter + // (\o -> + // case o.ref of + // StartingLocation -> + // True + + // _ -> + // False + // ) + // state.overlays + // in + // { game | state = { state | players = players, pieces = assignPlayersToPiece players filteredPieces statingLocations } } + + + // assignPlayersToPiece : List CharacterClass -> List Piece -> List BoardOverlay -> List Piece + // assignPlayersToPiece players pieces startingLocations = + // let + // filteredLocations = + // filter + // (\o -> + // case o.ref of + // StartingLocation -> + // True + + // _ -> + // False + // ) + // startingLocations + // in + // case players of + // player :: rest -> + // case filteredLocations of + // location :: otherLocations -> + // case head location.cells of + // Just ( x, y ) -> + // assignPlayersToPiece rest (Piece (Player player) x y :: pieces) otherLocations + + // Nothing -> + // pieces + + // _ -> + // pieces + + // _ -> + // pieces + + + // ensureUniqueOverlays : Game -> Game + // ensureUniqueOverlays game = + // let + // state = + // game.state + + // overlays = + // state.overlays + // |> uniqueBy + // (\o -> + // cellsToString o.cells ++ Maybe.withDefault "" (getBoardOverlayName o.ref) + // ) + + // pieces = + // state.pieces + // |> uniqueBy + // (\p -> + // String.fromInt p.x ++ "x" ++ String.fromInt p.y + // ) + // in + // { game | state = { state | overlays = overlays, pieces = pieces } } + + + // cellsToString : List ( Int, Int ) -> String + // cellsToString cells = + // cells + // |> map (\( x, y ) -> String.fromInt x ++ "x" ++ String.fromInt y) + // |> foldl (\s b -> s ++ "|" ++ b) "" + +enum AIType: + case Enemy(monster: Monster) + case Summons(summons: SummonsType) + +enum SummonsType: + case NormalSummons(i: Int, color: Colour) // TODO: What is 'i'? + case BearSummons + +enum PieceType: + case None + case Player(cls: CharacterClass) + case AI(typ: AIType) + +final case class Piece + ( ref : PieceType + , x : Int + , y : Int + ) + +final case class Cell + ( rooms : List[MapTileRef] + , passable : Boolean + ) + +final case class Game + ( state : GameState + , scenario : Scenario + , seed : Random.Seed + , roomData : List[RoomData] + , staticBoard : List[List[Cell]] + ) + +final case class GameState + ( scenario : GameStateScenario + , players : List[CharacterClass] + , updateCount : Int + , visibleRooms : List[MapTileRef] + , overlays : List[BoardOverlay] + , pieces : List[Piece] + , availableMonsters : Map[String, List[Int]] + , roomCode : String + ) + +enum GameStateScenario: + case InbuiltScenario(exp: Expansion, i: Int) // TODO: What is 'i'? + case CustomScenario(data: String) + +enum Expansion: + case Gloomhaven + case Solo + +final case class RoomData + ( ref : MapTileRef + , origin : ( Int, Int ) + , turns : Int + ) diff --git a/ui/ui/src/vgb/Scenario.scala b/ui/ui/src/vgb/Scenario.scala new file mode 100644 index 00000000..2debf111 --- /dev/null +++ b/ui/ui/src/vgb/Scenario.scala @@ -0,0 +1,187 @@ +package vgb + +object Scenario: + + val empty: Scenario = + Scenario(0, "", MapTileData(MapTileRef.A1a, Nil, Nil, Nil, 0), 0, Nil) + +// mapTileDataToOverlayList : MapTileData -> Dict String ( List BoardOverlay, List ScenarioMonster ) +// mapTileDataToOverlayList data = +// let +// maxId = +// case +// List.map (\o -> o.id) data.overlays +// |> List.maximum +// of +// Just i -> +// i + 1 + +// Nothing -> +// 1 + +// initData = +// case refToString data.ref of +// Just ref -> +// ( data.overlays +// ++ List.indexedMap +// (\i d -> +// case d of +// DoorLink subType dir ( x, y ) _ l -> +// case subType of +// Corridor _ Two -> +// let +// turns = +// case dir of +// DiagonalLeft -> +// 1 + +// DiagonalRight -> +// 2 + +// _ -> +// 0 + +// coords2 = +// rotate ( x + 1, y ) ( x, y ) turns +// in +// BoardOverlay (Door subType [ data.ref, l.ref ]) (maxId + i) dir [ ( x, y ), coords2 ] + +// _ -> +// BoardOverlay (Door subType [ data.ref, l.ref ]) (maxId + i) dir [ ( x, y ) ] +// ) +// data.doors +// , data.monsters +// ) +// |> singleton ref + +// Nothing -> +// Dict.empty + +// doorData = +// List.map +// (\d -> +// case d of +// DoorLink _ _ _ _ map -> +// mapTileDataToOverlayList map +// ) +// data.doors +// |> List.foldl (\a b -> union a b) Dict.empty +// in +// union initData doorData + +// mapTileDataToList : MapTileData -> Maybe ( ( Int, Int ), ( Int, Int ) ) -> ( List MapTile, BoardBounds ) +// mapTileDataToList data maybeTurnAxis = +// let +// ( refPoint, origin ) = +// case maybeTurnAxis of +// Just ( r, o ) -> +// ( r, o ) + +// Nothing -> +// ( ( 0, 0 ), ( 0, 0 ) ) + +// mapTiles = +// (getMapTileListByRef data.ref +// ++ getMapTileListByObstacle data data.overlays +// ) +// |> List.map (normaliseAndRotateMapTile data.turns refPoint origin) + +// doorTiles = +// List.map (mapDoorDataToList data.ref refPoint origin data.turns) data.doors +// |> List.concat + +// allTiles = +// mapTiles ++ doorTiles + +// boundingBox = +// List.map (\m -> BoardBounds m.x m.x m.y m.y) allTiles +// |> List.foldl +// (\a b -> BoardBounds (min a.minX b.minX) (max a.maxX b.maxX) (min a.minY b.minY) (max a.maxY b.maxY)) +// (BoardBounds 0 0 0 0) +// in +// ( allTiles, boundingBox ) + + def getMapTileListByObstacle(mapTileData: MapTileData, boardOverlays: List[BoardOverlay]): List[MapTile] = + boardOverlays + .map(_.cells) + .foldLeft(List.empty[(Int, Int)])(_ ++ _) + .map { case (x, y) => MapTile(mapTileData.ref, x, y, mapTileData.turns, x, y, true, true) } + + def mapDoorDataToList( + prevRef: MapTileRef, + initRefPoint: (Int, Int), + initOrigin: (Int, Int), + initTurns: Int, + doorData: DoorData + ): List[MapTile] = + doorData match + case DoorData.DoorLink(_, _, r, origin, mapTileData) => + val refPoint = + normaliseAndRotatePoint(initTurns, initRefPoint, initOrigin, r) + + val doorTile = + MapTile(prevRef, refPoint._1, refPoint._2, initTurns, r._1, r._2, true, true) + + List(mapTileDataToList(mapTileData, (Option(refPoint, origin)))._1) + ++ List(doorTile) + + def normaliseAndRotateMapTile(turns: Int, refPoint: (Int, Int), origin: (Int, Int), mapTile: MapTile): MapTile = + val (rotatedX, rotatedY) = + normaliseAndRotatePoint(turns, refPoint, origin, (mapTile.x, mapTile.y)) + + mapTile.copy(x = rotatedX, y = rotatedY, turns = turns) + + def normaliseAndRotatePoint(turns: Int, refPoint: (Int, Int), origin: (Int, Int), tileCoord: (Int, Int)): (Int, Int) = + val (refPointX, refPointY, refPointZ) = + Hexagon.oddRowToCube(refPoint._1, refPoint._2) + + val (originX, originY, originZ) = + Hexagon.oddRowToCube(origin._1, origin._2) + + val (tileCoordX, tileCoordY, tileCoordZ) = + Hexagon.oddRowToCube(tileCoord._1, tileCoord._2) + + val initCoords = + Hexagon.cubeToOddRow( + tileCoordX - originX + refPointX, + tileCoordY - originY + refPointY, + tileCoordZ - originZ + refPointZ + ) + + Hexagon.rotate(initCoords, refPoint, turns) + +final case class BoardBounds(minX: Int, maxX: Int, minY: Int, maxY: Int) + +final case class MapTileData( + ref: MapTileRef, + doors: List[DoorData], + overlays: List[BoardOverlay], + monsters: List[ScenarioMonster], + turns: Int +) + +enum DoorData: + case DoorLink( + doorType: DoorSubType, + directionType: BoardOverlayDirectionType, + from: (Int, Int), + to: (Int, Int), + tileData: MapTileData + ) + +final case class ScenarioMonster( + monster: Monster, + initialX: Int, + initialY: Int, + twoPlayer: MonsterLevel, + threePlayer: MonsterLevel, + fourPlayer: MonsterLevel +) + +final case class Scenario( + id: Int, + title: String, + mapTilesData: MapTileData, + angle: Float, + additionalMonsters: List[MonsterType] +) From 4fcbc6efd79513efb9920ce5f43656d8516f4755 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sun, 9 Apr 2023 12:41:57 +0100 Subject: [PATCH 17/60] Ported BoardOverlay class --- ui/ui/src/vgb/BoardOverlay.scala | 369 ++++++++++++++++--------------- 1 file changed, 194 insertions(+), 175 deletions(-) diff --git a/ui/ui/src/vgb/BoardOverlay.scala b/ui/ui/src/vgb/BoardOverlay.scala index 6267b994..69450b1b 100644 --- a/ui/ui/src/vgb/BoardOverlay.scala +++ b/ui/ui/src/vgb/BoardOverlay.scala @@ -90,245 +90,264 @@ object BoardOverlay: ) } -// getBoardOverlayName : BoardOverlayType -> Maybe String -// getBoardOverlayName overlay = -// let -// compare = -// case overlay of -// Door d _ -> -// Door d , Nil - -// Treasure t -> -// case t of -// Chest _ -> -// Treasure (Chest Locked) - -// Coin _ -> -// Treasure (Coin 1) + def getBoardOverlayName(overlay: BoardOverlayType): Option[String] = { + val compare = + overlay match { + case BoardOverlayType.Door(d, _) => + BoardOverlayType.Door(d, Nil) + + case BoardOverlayType.Treasure(t) => + t match { + case TreasureSubType.Chest(_) => + BoardOverlayType.Treasure(TreasureSubType.Chest(ChestType.Locked)) + + case TreasureSubType.Coin(_) => + BoardOverlayType.Treasure(TreasureSubType.Coin(1)) + } + + case _ => + overlay + } + + overlayDictionary.filter(_ == compare).keys.headOption + } -// _ -> -// overlay -// in -// overlayDictionary -// |> Dict.filter (\_ v -> v == compare) -// |> Dict.keys -// |> List.head + def getBoardOverlayType(overlayName: String): Option[BoardOverlayType] = + overlayDictionary.get(overlayName) -// def getBoardOverlayType(overlayName: String): Option[BoardOverlayType] = -// overlayDictionary.get(overlayName) + def getAllOverlayTypes: List[BoardOverlayType] = + overlayDictionary.values.toList -// def getAllOverlayTypes: List[BoardOverlayType] = -// overlayDictionary.values.toList + def getOverlayTypesWithLabel: Map[String, BoardOverlayType] = + overlayDictionary -// def getOverlayTypesWithLabel: Map[String, BoardOverlayType] = -// overlayDictionary + def getOverlayLabel(overlay: BoardOverlayType): String = { + import BoardOverlayType.* + import DoorSubType.* + import CorridorSize.* + import CorridorMaterial.* + import DifficultTerrainSubType.* + import WallSubType.* + import ObstacleSubType.* + import HazardSubType.* + import TreasureSubType.* + import ChestType.* + import TrapSubType.* -// getOverlayLabel : BoardOverlayType -> String -// getOverlayLabel overlay = -// case overlay of -// Door d _ -> -// case d of -// AltarDoor -> -// "Altar" + overlay match { + case Door(d, _) => + d match { + case AltarDoor => + "Altar" -// Stone -> -// "Stone Door" + case Stone => + "Stone Door" -// Wooden -> -// "Wooden Door" + case Wooden => + "Wooden Door" -// BreakableWall -> -// "Breakable Wall" + case BreakableWall => + "Breakable Wall" -// Corridor c _ -> -// case c of -// Dark -> -// "Dark Corridor" + case Corridor(c, _) => + c match { + case Dark => + "Dark Corridor" -// Earth -> -// "Earth Corridor" + case Earth => + "Earth Corridor" -// ManmadeStone -> -// "Manmade Stone Corridor" + case ManmadeStone => + "Manmade Stone Corridor" -// NaturalStone -> -// "Natural Stone Corridor" + case NaturalStone => + "Natural Stone Corridor" -// PressurePlate -> -// "Pressure Plate" + case PressurePlate => + "Pressure Plate" -// Wood -> -// "Wooden Corridor" + case Wood => + "Wooden Corridor" + } -// DarkFog -> -// "Dark Fog" + case DarkFog => + "Dark Fog" -// LightFog -> -// "Light Fog" + case LightFog => + "Light Fog" + } -// DifficultTerrain d -> -// case d of -// Log -> -// "Fallen Log" + case DifficultTerrain(d) => + d match { + case Log => + "Fallen Log" -// Rubble -> -// "Rubble" + case Rubble => + "Rubble" -// Stairs -> -// "Stairs" + case Stairs => + "Stairs" -// VerticalStairs -> -// "Stairs" + case VerticalStairs => + "Stairs" -// Water -> -// "Water" + case Water => + "Water" + } -// Hazard h -> -// case h of -// HotCoals -> -// "Hot Coals" + case Hazard(h) => + h match { + case HotCoals => + "Hot Coals" -// Thorns -> -// "Thorns" + case Thorns => + "Thorns" + } -// Highlight c -> -// Colour.toString c ++ " Highlight" + case Highlight(c) => + c.toString ++ " Highlight" -// Obstacle o -> -// case o of -// Altar -> -// "Altar" + case Obstacle(o) => + o match { + case Altar => + "Altar" -// Barrel -> -// "Barrel" + case Barrel => + "Barrel" -// Bookcase -> -// "Bookcase" + case Bookcase => + "Bookcase" -// Boulder1 -> -// "Boulder" + case Boulder1 => + "Boulder" -// Boulder2 -> -// "Boulder" + case Boulder2 => + "Boulder" -// Boulder3 -> -// "Boulder" + case Boulder3 => + "Boulder" -// Bush -> -// "Bush" + case Bush => + "Bush" -// Cabinet -> -// "Cabinet" + case Cabinet => + "Cabinet" -// Crate -> -// "Crate" + case Crate => + "Crate" -// Crystal -> -// "Crystal" + case Crystal => + "Crystal" -// DarkPit -> -// "Dark Pit" + case DarkPit => + "Dark Pit" -// Fountain -> -// "Fountain" + case Fountain => + "Fountain" -// Mirror -> -// "Mirror" + case Mirror => + "Mirror" -// Nest -> -// "Nest" + case Nest => + "Nest" -// Pillar -> -// "Pillar" + case Pillar => + "Pillar" -// RockColumn -> -// "Rock Column" + case RockColumn => + "Rock Column" -// Sarcophagus -> -// "Sarcophagus" + case Sarcophagus => + "Sarcophagus" -// Shelf -> -// "Sheelves" + case Shelf => + "Sheelves" -// Stalagmites -> -// "Stalagmites" + case Stalagmites => + "Stalagmites" -// Stump -> -// "Tree Stump" + case Stump => + "Tree Stump" -// Table -> -// "Table" + case Table => + "Table" -// Totem -> -// "Totem" + case Totem => + "Totem" -// Tree3 -> -// "Tree" + case Tree3 => + "Tree" -// WallSection -> -// "Wall" + case WallSection => + "Wall" + } -// Rift -> -// "Rift" + case Rift => + "Rift" -// StartingLocation -> -// "Starting Location" + case StartingLocation => + "Starting Location" -// Trap t -> -// case t of -// BearTrap -> -// "Bear Trap" + case Trap(t) => + t match { + case BearTrap => + "Bear Trap" -// Spike -> -// "Spike Trap" + case Spike => + "Spike Trap" -// Poison -> -// "Poison Trap" + case Poison => + "Poison Trap" + } -// Treasure t -> -// case t of -// Chest c -> -// "Treasure Chest " -// ++ (case c of -// Goal -> -// "Goal" + case Treasure(t) => + t match { + case Chest(c) => + "Treasure Chest " + ++ (c match { + case Goal => + "Goal" -// Locked -> -// "(locked)" + case Locked => + "(locked)" -// NormalChest i -> -// String.fromInt i -// ) + case NormalChest(i) => + i.toString + }) -// Coin i -> -// String.fromInt i -// ++ (case i of -// 1 -> -// " Coin" + case Coin(i) => + i.toString + ++ (i match { + case 1 => + " Coin" -// _ -> -// " Coins" -// ) + case _ => + " Coins" + }) + } -// Token t -> -// "Token (" ++ t ++ ")" + case Token(t) => + "Token (" ++ t ++ ")" -// Wall w -> -// case w of -// HugeRock -> -// "Huge Rock Wall" + case Wall(w) => + w match { + case HugeRock => + "Huge Rock Wall" -// Iron -> -// "Iron Wall" + case Iron => + "Iron Wall" -// LargeRock -> -// "Large Rock Wall" + case LargeRock => + "Large Rock Wall" -// ObsidianGlass -> -// "Obsidian Glass Wall" + case ObsidianGlass => + "Obsidian Glass Wall" -// Rock -> -// "Rock Wall" + case Rock => + "Rock Wall" + } + } + } enum BoardOverlayType: case DifficultTerrain(typ: DifficultTerrainSubType) From 3e0a233562585f0af42fb77f66db6d9ebc796abc Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sun, 9 Apr 2023 14:24:16 +0100 Subject: [PATCH 18/60] Ported Scenario class --- ui/ui/src/vgb/Scenario.scala | 203 ++++++++++++++++++----------------- 1 file changed, 107 insertions(+), 96 deletions(-) diff --git a/ui/ui/src/vgb/Scenario.scala b/ui/ui/src/vgb/Scenario.scala index 2debf111..a0b2da54 100644 --- a/ui/ui/src/vgb/Scenario.scala +++ b/ui/ui/src/vgb/Scenario.scala @@ -5,101 +5,112 @@ object Scenario: val empty: Scenario = Scenario(0, "", MapTileData(MapTileRef.A1a, Nil, Nil, Nil, 0), 0, Nil) -// mapTileDataToOverlayList : MapTileData -> Dict String ( List BoardOverlay, List ScenarioMonster ) -// mapTileDataToOverlayList data = -// let -// maxId = -// case -// List.map (\o -> o.id) data.overlays -// |> List.maximum -// of -// Just i -> -// i + 1 - -// Nothing -> -// 1 - -// initData = -// case refToString data.ref of -// Just ref -> -// ( data.overlays -// ++ List.indexedMap -// (\i d -> -// case d of -// DoorLink subType dir ( x, y ) _ l -> -// case subType of -// Corridor _ Two -> -// let -// turns = -// case dir of -// DiagonalLeft -> -// 1 - -// DiagonalRight -> -// 2 - -// _ -> -// 0 - -// coords2 = -// rotate ( x + 1, y ) ( x, y ) turns -// in -// BoardOverlay (Door subType [ data.ref, l.ref ]) (maxId + i) dir [ ( x, y ), coords2 ] - -// _ -> -// BoardOverlay (Door subType [ data.ref, l.ref ]) (maxId + i) dir [ ( x, y ) ] -// ) -// data.doors -// , data.monsters -// ) -// |> singleton ref - -// Nothing -> -// Dict.empty - -// doorData = -// List.map -// (\d -> -// case d of -// DoorLink _ _ _ _ map -> -// mapTileDataToOverlayList map -// ) -// data.doors -// |> List.foldl (\a b -> union a b) Dict.empty -// in -// union initData doorData - -// mapTileDataToList : MapTileData -> Maybe ( ( Int, Int ), ( Int, Int ) ) -> ( List MapTile, BoardBounds ) -// mapTileDataToList data maybeTurnAxis = -// let -// ( refPoint, origin ) = -// case maybeTurnAxis of -// Just ( r, o ) -> -// ( r, o ) - -// Nothing -> -// ( ( 0, 0 ), ( 0, 0 ) ) - -// mapTiles = -// (getMapTileListByRef data.ref -// ++ getMapTileListByObstacle data data.overlays -// ) -// |> List.map (normaliseAndRotateMapTile data.turns refPoint origin) - -// doorTiles = -// List.map (mapDoorDataToList data.ref refPoint origin data.turns) data.doors -// |> List.concat - -// allTiles = -// mapTiles ++ doorTiles - -// boundingBox = -// List.map (\m -> BoardBounds m.x m.x m.y m.y) allTiles -// |> List.foldl -// (\a b -> BoardBounds (min a.minX b.minX) (max a.maxX b.maxX) (min a.minY b.minY) (max a.maxY b.maxY)) -// (BoardBounds 0 0 0 0) -// in -// ( allTiles, boundingBox ) + def mapTileDataToOverlayList(data: MapTileData): Map[String, (List[BoardOverlay], List[ScenarioMonster])] = + val maxId = + data.overlays.map(_.id).maxOption match + case Some(i) => + i + 1 + + case None => + 1 + + val initData: Map[String, (List[BoardOverlay], List[ScenarioMonster])] = + BoardMapTile.refToString(data.ref) match + case Some(ref) => + val t = + ( + data.overlays ++ + data.doors.zipWithIndex.map { case (d, i) => + d match { + case DoorData.DoorLink(subType, dir, (x, y), _, l) => + subType match { + case DoorSubType.Corridor(_, CorridorSize.Two) => + val turns = + dir match { + case BoardOverlayDirectionType.DiagonalLeft => + 1 + + case BoardOverlayDirectionType.DiagonalRight => + 2 + + case _ => + 0 + } + + val coords2 = + Hexagon.rotate((x + 1, y), (x, y), turns) + + BoardOverlay( + BoardOverlayType.Door(subType, List(data.ref, l.ref)), + (maxId + i), + dir, + List((x, y), coords2) + ) + + case _ => + BoardOverlay( + BoardOverlayType.Door(subType, List(data.ref, l.ref)), + (maxId + i), + dir, + List((x, y)) + ) + } + } + }, + data.monsters + ) + + Map(ref -> t) + + case None => + Map.empty + + val doorData = + data.doors + .map { case DoorData.DoorLink(_, _, _, _, map) => + mapTileDataToOverlayList(map) + } + .foldLeft(Map.empty[String, (List[BoardOverlay], List[ScenarioMonster])]) { case (a, b) => a ++ b } + + initData ++ doorData + + def mapTileDataToList( + data: MapTileData, + maybeTurnAxis: Option[((Int, Int), (Int, Int))] + ): (List[MapTile], BoardBounds) = + val (refPoint, origin) = + maybeTurnAxis match + case Some(r, o) => + (r, o) + + case None => + ((0, 0), (0, 0)) + + val mapTiles = + (BoardMapTile.getMapTileListByRef(data.ref) + ++ getMapTileListByObstacle(data, data.overlays)).map(mapTile => + normaliseAndRotateMapTile(data.turns, refPoint, origin, mapTile) + ) + + val doorTiles = + data.doors.flatMap(door => mapDoorDataToList(data.ref, refPoint, origin, data.turns, door)) + + val allTiles = + mapTiles ++ doorTiles + + val boundingBox = + allTiles + .map(m => BoardBounds(m.x, m.x, m.y, m.y)) + .foldLeft(BoardBounds(0, 0, 0, 0)) { case (a, b) => + BoardBounds( + Math.min(a.minX, b.minX), + Math.max(a.maxX, b.maxX), + Math.min(a.minY, b.minY), + Math.max(a.maxY, b.maxY) + ) + } + + (allTiles, boundingBox) def getMapTileListByObstacle(mapTileData: MapTileData, boardOverlays: List[BoardOverlay]): List[MapTile] = boardOverlays @@ -122,7 +133,7 @@ object Scenario: val doorTile = MapTile(prevRef, refPoint._1, refPoint._2, initTurns, r._1, r._2, true, true) - List(mapTileDataToList(mapTileData, (Option(refPoint, origin)))._1) + mapTileDataToList(mapTileData, (Option(refPoint, origin)))._1 ++ List(doorTile) def normaliseAndRotateMapTile(turns: Int, refPoint: (Int, Int), origin: (Int, Int), mapTile: MapTile): MapTile = From 1c7f3ff3d6ba8b76f6a104f7c1ca86d7f24e62f0 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sun, 9 Apr 2023 16:14:33 +0100 Subject: [PATCH 19/60] WIP --- ui/ui/src/vgb/BoardHtml.scala | 1102 +++++++++++++++++++++++++++++++++ ui/ui/src/vgb/Game.scala | 65 +- 2 files changed, 1132 insertions(+), 35 deletions(-) create mode 100644 ui/ui/src/vgb/BoardHtml.scala diff --git a/ui/ui/src/vgb/BoardHtml.scala b/ui/ui/src/vgb/BoardHtml.scala new file mode 100644 index 00000000..c62d75a6 --- /dev/null +++ b/ui/ui/src/vgb/BoardHtml.scala @@ -0,0 +1,1102 @@ +package vgb + +import tyrian.Html.* + +object BoardHtml { + + def getMapTileHtml( + visibleRooms: List[MapTileRef], + roomData: List[RoomData], + currentDraggable: String, + draggableX: Int, + draggableY: Int + ): Html[Msg] = + div(`class` := "mapTiles")( + roomData + .distinctBy(d => BoardMapTile.refToString(d.ref).getOrElse("")) + .map { r => + val isVisible = visibleRooms.contains(r.ref) + val ref = BoardMapTile.refToString(r.ref).getOrElse("") + val (x, y) = + if ref == currentDraggable then (draggableX, draggableY) + else r.origin + + getSingleMapTileHtml(isVisible, ref, r.turns, x, y) + } + ) + +// getAllMapTileHtml : List RoomData -> String -> Int -> Int -> Html.Html Msg +// getAllMapTileHtml roomData currentDraggable draggableX draggableY = +// let +// allRooms = +// if List.member currentDraggable (List.map (\r -> Maybe.withDefault "" (refToString r.ref)) roomData) then +// roomData + +// else +// case stringToRef currentDraggable of +// Just r -> +// RoomData r ( draggableX, draggableY ) 0 :: roomData + +// Nothing -> +// roomData +// in +// getMapTileHtml (map (\d -> d.ref) allRooms) allRooms currentDraggable draggableX draggableY + +// getSingleMapTileHtml : Bool -> String -> Int -> Int -> Int -> Html.Html Msg +// getSingleMapTileHtml isVisible ref turns x y = +// let +// xPx = +// (x * 76) +// + (if Bitwise.and y 1 == 1 then +// 38 + +// else +// 0 +// ) + +// yPx = +// y * 67 +// in +// div +// [] +// [ div +// [ class "mapTile" +// , class ("rotate-" ++ String.fromInt turns) +// , class +// (if isVisible then +// "visible" + +// else +// "hidden" +// ) +// , style "top" (String.fromInt yPx ++ "px") +// , style "left" (String.fromInt xPx ++ "px") +// ] +// [ img +// [ src ("/img/map-tiles/" ++ ref ++ ".png") +// , class ("ref-" ++ ref) +// , alt ("Map tile " ++ ref) +// , attribute "aria-hidden" +// (if isVisible then +// "false" + +// else +// "true" +// ) +// ] +// [] +// ] +// , div +// [ class "mapTile outline" +// , class ("rotate-" ++ String.fromInt turns) +// , class +// (if isVisible then +// "hidden" + +// else +// "visible" +// ) +// , style "top" (String.fromInt yPx ++ "px") +// , style "left" (String.fromInt xPx ++ "px") +// , attribute "aria-hidden" +// (if isVisible then +// "true" + +// else +// "false" +// ) +// ] +// (case stringToRef ref of +// Nothing -> +// [] + +// Just Empty -> +// [] + +// Just r -> +// let +// overlayPrefix = +// case r of +// J1a -> +// "ja" + +// J2a -> +// "ja" + +// J1b -> +// "jb" + +// J1ba -> +// "jb" + +// J1bb -> +// "jb" + +// J2b -> +// "jb" + +// _ -> +// String.left 1 ref +// in +// [ img +// [ src ("/img/map-tiles/" ++ overlayPrefix ++ "-outline.png") +// , class ("ref-" ++ ref) +// , alt ("The outline of map tile " ++ ref) +// ] +// [] +// ] +// ) +// ] + +// getCellHtml : CellModel Msg -> Dom.Element Msg +// getCellHtml model = +// let +// ( x, y ) = +// model.coords + +// currentDraggable = +// model.currentDraggable + +// overlaysForCell = +// List.filter (filterOverlaysForCoord x y) model.overlays +// |> map +// (\o -> +// BoardOverlayModel +// (case currentDraggable of +// Just m -> +// case m.ref of +// OverlayType ot _ -> +// let +// isInCoords = +// case m.coords of +// Just ( ox, oy ) -> +// any (\c -> c == ( ox, oy )) o.cells + +// Nothing -> +// False + +// isInTarget = +// case m.target of +// Just ( ox, oy ) -> +// any (\c -> c == ( ox, oy )) o.cells + +// Nothing -> +// False +// in +// ot.ref == o.ref && (isInCoords || isInTarget) + +// _ -> +// False + +// Nothing -> +// False +// ) +// (Just ( x, y )) +// o +// model.dragEvents +// ) + +// piece = +// Maybe.map +// (\p -> +// PieceModel +// (case currentDraggable of +// Just m -> +// case m.ref of +// PieceType pieceType -> +// pieceType.ref == p.ref + +// _ -> +// False + +// Nothing -> +// False +// ) +// (Just ( x, y )) +// p +// model.dragEvents +// ) +// (getPieceForCoord x y model.pieces) + +// monster = +// Maybe.map +// (\m -> +// ScenarioMonsterModel +// (case currentDraggable of +// Just c -> +// case c.ref of +// PieceType p -> +// case p.ref of +// AI (Enemy e) -> +// e == m.monster + +// _ -> +// False + +// _ -> +// False + +// Nothing -> +// False +// ) +// (Just ( x, y )) +// m +// model.dragEvents +// ) +// (getScenarioMonsterForCoord x y model.scenarioMonsters) + +// cellElement : Dom.Element Msg +// cellElement = +// Dom.element "div" +// |> Dom.addClass "hexagon" +// |> Dom.addAttribute (attribute "data-cell-x" (String.fromInt x)) +// |> Dom.addAttribute (attribute "data-cell-y" (String.fromInt y)) +// -- Everything except coins and tokens +// |> Dom.setChildListWithKeys +// ((overlaysForCell +// |> List.sortWith +// (\a b -> +// compare (getSortOrderForOverlay a.overlay.ref) (getSortOrderForOverlay b.overlay.ref) +// ) +// |> List.filter +// (\o -> +// case o.overlay.ref of +// Treasure t -> +// case t of +// Chest _ -> +// True + +// _ -> +// False + +// Token _ -> +// False + +// _ -> +// True +// ) +// |> List.map (overlayToHtml model.dragOverlays model.dragDoors) +// ) +// ++ -- Players / Monsters / Summons +// (case piece of +// Nothing -> +// [] + +// Just p -> +// [ pieceToHtml model.dragPieces p ] +// ) +// ++ (case monster of +// Nothing -> +// [] + +// Just m -> +// [ scenarioMonsterToHtml model.dragPieces m ] +// ) +// ++ -- Coins +// (overlaysForCell +// |> List.filter +// (\o -> +// case o.overlay.ref of +// Treasure t -> +// case t of +// Chest _ -> +// False + +// _ -> +// True + +// Token _ -> +// True + +// _ -> +// False +// ) +// |> List.map (overlayToHtml model.dragOverlays model.dragDoors) +// ) +// ++ -- The current draggable piece +// (case currentDraggable of +// Just m -> +// case m.ref of +// PieceType p -> +// if m.target == Just ( x, y ) then +// [ pieceToHtml +// model.dragPieces +// (PieceModel +// False +// (Just ( x, y )) +// p +// model.dragEvents +// ) +// ] + +// else +// [] + +// OverlayType o _ -> +// if any (\c -> c == ( x, y )) o.cells then +// [ overlayToHtml +// model.dragOverlays +// model.dragDoors +// (BoardOverlayModel +// False +// (Just ( x, y )) +// o +// model.dragEvents +// ) +// ] + +// else +// [] + +// RoomType _ -> +// [] + +// Nothing -> +// [] +// ) +// ) +// in +// Dom.element "div" +// |> Dom.addClass "cell-wrapper" +// |> Dom.addClass (cellValueToString model.passable model.hidden) +// |> Dom.appendChild +// (Dom.element "div" +// |> Dom.addClass "cell" +// |> Dom.appendChild cellElement +// ) +// |> (\e -> +// if model.passable == True && model.hidden == False then +// makeDroppable ( x, y ) model.dropEvents e + +// else +// e +// ) + +// getPieceForCoord : Int -> Int -> List Piece -> Maybe Piece +// getPieceForCoord x y pieces = +// List.filter (\p -> p.x == x && p.y == y) pieces +// |> List.head + +// getScenarioMonsterForCoord : Int -> Int -> List ScenarioMonster -> Maybe ScenarioMonster +// getScenarioMonsterForCoord x y monsters = +// List.filter (\m -> m.initialX == x && m.initialY == y) monsters +// |> List.head + +// filterOverlaysForCoord : Int -> Int -> BoardOverlay -> Bool +// filterOverlaysForCoord x y overlay = +// case List.head (List.filter (\( oX, oY ) -> oX == x && oY == y) overlay.cells) of +// Just _ -> +// True + +// Nothing -> +// False + +// getSortOrderForOverlay : BoardOverlayType -> Int +// getSortOrderForOverlay overlay = +// case overlay of +// Token _ -> +// 0 + +// Door _ _ -> +// 1 + +// Hazard _ -> +// 2 + +// DifficultTerrain _ -> +// 3 + +// StartingLocation -> +// 4 + +// Rift -> +// 5 + +// Treasure t -> +// case t of +// Chest _ -> +// 6 + +// Coin _ -> +// 7 + +// Obstacle _ -> +// 8 + +// Trap _ -> +// 9 + +// Wall _ -> +// 10 + +// Highlight _ -> +// 11 + +// overlayToHtml : Bool -> Bool -> BoardOverlayModel Msg -> ( String, Dom.Element Msg ) +// overlayToHtml dragOverlays dragDoors model = +// let +// label = +// getLabelForOverlay model.overlay model.coords +// in +// ( label +// , Dom.element "div" +// |> Dom.addAttribute +// (attribute "aria-label" label) +// |> Dom.addClass "overlay" +// |> Dom.addClassConditional "being-dragged" model.isDragging +// |> Dom.addClass +// (case model.overlay.ref of +// StartingLocation -> +// "start-location" + +// Rift -> +// "rift" + +// Treasure t -> +// "treasure " +// ++ (case t of +// Coin _ -> +// "coin" + +// Chest _ -> +// "chest" +// ) + +// Obstacle _ -> +// "obstacle" + +// Hazard _ -> +// "hazard" + +// Highlight _ -> +// "highlight" + +// DifficultTerrain _ -> +// "difficult-terrain" + +// Door c _ -> +// "door" +// ++ (case c of +// Corridor _ _ -> +// " corridor" + +// _ -> +// "" +// ) + +// Trap _ -> +// "trap" + +// Token _ -> +// "token" + +// Wall _ -> +// "wall" +// ) +// |> Dom.addClass +// (case model.overlay.direction of +// Default -> +// "" + +// Vertical -> +// "vertical" + +// VerticalReverse -> +// "vertical-reverse" + +// Horizontal -> +// "horizontal" + +// DiagonalRight -> +// "diagonal-right" + +// DiagonalLeft -> +// "diagonal-left" + +// DiagonalRightReverse -> +// "diagonal-right-reverse" + +// DiagonalLeftReverse -> +// "diagonal-left-reverse" +// ) +// |> Dom.addAttributeConditional +// (attribute "data-index" +// (case model.overlay.ref of +// Treasure t -> +// case t of +// Chest c -> +// case c of +// NormalChest i -> +// String.fromInt i + +// Goal -> +// "Goal" + +// Locked -> +// "???" + +// _ -> +// "" + +// _ -> +// "" +// ) +// ) +// (case model.overlay.ref of +// Treasure _ -> +// True + +// _ -> +// False +// ) +// |> Dom.appendChild +// (case model.overlay.ref of +// Token val -> +// Dom.element "span" +// |> Dom.appendText val + +// Highlight c -> +// Dom.element "div" +// |> Dom.addStyle ( "background-color", Colour.toHexString c ) + +// _ -> +// Dom.element "img" +// |> Dom.addAttribute (alt (getOverlayLabel model.overlay.ref)) +// |> Dom.addAttribute (attribute "src" (getOverlayImageName model.overlay model.coords)) +// |> Dom.addAttribute (attribute "draggable" "false") +// ) +// |> (case model.overlay.ref of +// Treasure (Coin i) -> +// Dom.appendChild +// (Dom.element "span" +// |> Dom.appendText (String.fromInt i) +// ) + +// _ -> +// \e -> e +// ) +// |> (if dragOverlays then +// case model.overlay.ref of +// Treasure (Coin _) -> +// if model.coords == Nothing then +// makeDraggable (OverlayType model.overlay Nothing) model.coords model.dragEvents + +// else +// Dom.addAttribute (attribute "draggable" "false") + +// Treasure (Chest _) -> +// Dom.addAttribute (attribute "draggable" "false") + +// Highlight _ -> +// Dom.addAttribute (attribute "draggable" "false") + +// Door _ _ -> +// if dragDoors then +// \e -> e + +// else +// Dom.addAttribute (attribute "draggable" "false") + +// _ -> +// makeDraggable (OverlayType model.overlay Nothing) model.coords model.dragEvents + +// else +// \e -> e +// ) +// |> (if dragDoors then +// case model.overlay.ref of +// Door _ _ -> +// makeDraggable (OverlayType model.overlay Nothing) model.coords model.dragEvents + +// _ -> +// if dragOverlays then +// \e -> e + +// else +// Dom.addAttribute (attribute "draggable" "false") + +// else +// \e -> e +// ) +// ) + +// pieceToHtml : Bool -> PieceModel Msg -> ( String, Dom.Element Msg ) +// pieceToHtml dragPiece model = +// let +// label = +// getLabelForPiece model.piece + +// playerHtml : String -> String -> Element Msg -> Element Msg +// playerHtml l p e = +// Dom.addClass "hex-mask" e +// |> Dom.appendChild +// (Dom.element "img" +// |> Dom.addAttribute (alt l) +// |> Dom.addAttribute (attribute "src" ("/img/characters/portraits/" ++ p ++ ".png")) +// ) +// in +// ( label +// , Dom.element "div" +// |> Dom.addAttribute +// (attribute "aria-label" +// (case model.coords of +// Just ( x, y ) -> +// label ++ " at " ++ String.fromInt x ++ ", " ++ String.fromInt y + +// Nothing -> +// "Add New " ++ label +// ) +// ) +// |> Dom.addClass (getPieceType model.piece.ref) +// |> Dom.addClass (getPieceName model.piece.ref) +// |> Dom.addClassConditional "being-dragged" model.isDragging +// |> (case model.piece.ref of +// Player p -> +// playerHtml label (Maybe.withDefault "" (characterToString p)) + +// AI t -> +// case t of +// Enemy m -> +// enemyToHtml m label + +// Summons (NormalSummons i colour) -> +// Dom.appendChildList +// [ Dom.element "img" +// |> Dom.addAttribute (alt label) +// |> Dom.addAttribute (attribute "src" "/img/characters/summons.png") +// |> Dom.addAttribute (attribute "draggable" "false") +// , Dom.element "span" |> Dom.appendText (String.fromInt i) +// ] + +// Summons BearSummons -> +// \e -> +// Dom.addClass "bear" e +// |> playerHtml label "bear" + +// Game.None -> +// Dom.addClass "none" +// ) +// |> (if dragPiece then +// makeDraggable (PieceType model.piece) model.coords model.dragEvents + +// else +// \e -> e +// ) +// ) + +// scenarioMonsterToHtml : Bool -> ScenarioMonsterModel Msg -> ( String, Dom.Element Msg ) +// scenarioMonsterToHtml dragPiece model = +// let +// monster = +// model.monster + +// label = +// Maybe.withDefault "" (monsterTypeToString monster.monster.monster) +// |> String.replace "-" " " + +// pieceModel = +// { ref = AI (Enemy monster.monster) +// , x = monster.initialX +// , y = monster.initialY +// } +// in +// ( label +// , Dom.element "div" +// |> Dom.addAttribute +// (attribute "aria-label" +// (case model.coords of +// Just ( x, y ) -> +// label ++ " at " ++ String.fromInt x ++ ", " ++ String.fromInt y + +// Nothing -> +// "Add New " ++ label +// ) +// ) +// |> Dom.addClass "monster" +// |> Dom.addClass (Maybe.withDefault "" (monsterTypeToString model.monster.monster.monster)) +// |> Dom.addClassConditional "being-dragged" model.isDragging +// |> enemyToHtml monster.monster label +// |> Dom.appendChild +// (scenarioMonsterVisibilityToHtml monster.twoPlayer +// |> Dom.addClass "two-player" +// ) +// |> Dom.appendChild +// (scenarioMonsterVisibilityToHtml monster.threePlayer +// |> Dom.addClass "three-player" +// ) +// |> Dom.appendChild +// (scenarioMonsterVisibilityToHtml monster.fourPlayer +// |> Dom.addClass "four-player" +// ) +// |> (if dragPiece then +// makeDraggable (PieceType pieceModel) model.coords model.dragEvents + +// else +// \e -> e +// ) +// ) + +// cellValueToString : Bool -> Bool -> String +// cellValueToString passable hidden = +// if hidden then +// "hidden" + +// else if passable then +// "passable" + +// else +// "impassable" + +// getLabelForOverlay : BoardOverlay -> Maybe ( Int, Int ) -> String +// getLabelForOverlay overlay coords = +// case coords of +// Just ( x, y ) -> +// getOverlayLabel overlay.ref ++ " at " ++ String.fromInt x ++ ", " ++ String.fromInt y + +// Nothing -> +// "Add new " ++ getOverlayLabel overlay.ref + +// getLabelForPiece : Piece -> String +// getLabelForPiece piece = +// case piece.ref of +// Player p -> +// Maybe.withDefault "" (characterToString p) +// |> String.replace "-" " " + +// AI t -> +// case t of +// Enemy m -> +// (case m.monster of +// NormalType _ -> +// case m.level of +// Elite -> +// "Elite" + +// Normal -> +// "Normal" + +// Monster.None -> +// "" + +// BossType _ -> +// "Boss" +// ) +// ++ " " +// ++ (Maybe.withDefault "" (monsterTypeToString m.monster) +// |> String.replace "-" " " +// ) +// ++ (if m.id > 0 then +// " (" ++ String.fromInt m.id ++ ")" + +// else +// "" +// ) + +// Summons (NormalSummons i _) -> +// "Summons Number " ++ String.fromInt i + +// Summons BearSummons -> +// "Beast Tyrant Bear Summons" + +// Game.None -> +// "None" + +// getOverlayImageName : BoardOverlay -> Maybe ( Int, Int ) -> String +// getOverlayImageName overlay coords = +// let +// path = +// "/img/overlays/" + +// overlayName = +// Maybe.withDefault "" (getBoardOverlayName overlay.ref) + +// extension = +// ".png" + +// extendedOverlayName = +// if overlay.direction == Vertical || overlay.direction == VerticalReverse then +// case overlay.ref of +// Door Stone _ -> +// "-vert" + +// Door BreakableWall _ -> +// "-vert" + +// Door Wooden _ -> +// "-vert" + +// Obstacle Altar -> +// "-vert" + +// _ -> +// "" + +// else +// "" + +// segmentPart = +// case coords of +// Just ( x, y ) -> +// case List.head (List.filter (\( _, ( oX, oY ) ) -> oX == x && oY == y) (toIndexedList (fromList overlay.cells))) of +// Just ( segment, _ ) -> +// if segment > 0 then +// "-" ++ String.fromInt (segment + 1) + +// else +// "" + +// Nothing -> +// "" + +// Nothing -> +// "" +// in +// path ++ overlayName ++ extendedOverlayName ++ segmentPart ++ extension + +// enemyToHtml : Monster -> String -> Element Msg -> Element Msg +// enemyToHtml monster altText element = +// let +// class = +// case monster.monster of +// NormalType _ -> +// case monster.level of +// Elite -> +// "elite" + +// Normal -> +// "normal" + +// Monster.None -> +// "" + +// BossType _ -> +// "boss" +// in +// element +// |> Dom.addClass class +// |> Dom.addClass "hex-mask" +// |> Dom.appendChildList +// [ Dom.element "img" +// |> Dom.addAttribute +// (attribute "src" +// ("/img/monsters/" +// ++ Maybe.withDefault "" (monsterTypeToString monster.monster) +// ++ ".png" +// ) +// ) +// |> Dom.addAttribute (alt altText) +// , Dom.element "span" +// |> Dom.appendText +// (if monster.id == 0 then +// "" + +// else +// String.fromInt monster.id +// ) +// ] + +// scenarioMonsterVisibilityToHtml : MonsterLevel -> Element Msg +// scenarioMonsterVisibilityToHtml level = +// Dom.element "div" +// |> Dom.addClass "monster-visibility" +// |> Dom.addClass +// (case level of +// Normal -> +// "normal" + +// Elite -> +// "elite" + +// Monster.None -> +// "none" +// ) + +// makeDraggable : MoveablePieceType -> Maybe ( Int, Int ) -> DragEvents Msg -> Element Msg -> Element Msg +// makeDraggable piece coords dragEvents element = +// let +// config = +// DragDrop.DraggedSourceConfig +// (DragDrop.EffectAllowed True False False) +// (\e v -> dragEvents.moveStart (MoveablePiece piece coords Nothing) (Just ( e, v ))) +// (always dragEvents.moveCancel) +// Nothing +// in +// element +// |> Dom.addAttributeList (DragDrop.onSourceDrag config) +// |> Dom.addAttribute (Touch.onStart (\_ -> dragEvents.touchStart (MoveablePiece piece coords Nothing))) +// |> Dom.addAttribute +// (Touch.onMove +// (\e -> +// case List.head e.touches of +// Just touch -> +// dragEvents.touchMove touch.clientPos + +// Nothing -> +// dragEvents.noOp +// ) +// ) +// |> Dom.addAttribute +// (Touch.onEnd +// (\e -> +// case List.head e.changedTouches of +// Just touch -> +// dragEvents.touchEnd touch.clientPos + +// Nothing -> +// dragEvents.noOp +// ) +// ) + +// makeDroppable : ( Int, Int ) -> DropEvents Msg -> Element Msg -> Element Msg +// makeDroppable coords dropEvents element = +// let +// config = +// DragDrop.DropTargetConfig +// DragDrop.MoveOnDrop +// (\e v -> dropEvents.moveTargetChanged coords (Just ( e, v ))) +// (always dropEvents.moveCompleted) +// Nothing +// Nothing +// in +// element +// |> Dom.addAttributeList (DragDrop.onDropTarget config) + +// getFooterHtml : String -> Html.Html Msg +// getFooterHtml v = +// footer [] +// [ div [ class "credits" ] +// [ span [ class "gloomCopy" ] +// [ text "Gloomhaven and all related properties and images are owned by " +// , a [ href "http://www.cephalofair.com/" ] [ text "Cephalofair Games" ] +// ] +// , span [ class "any2CardCopy" ] +// [ text "Additional card scans courtesy of " +// , a [ href "https://github.com/any2cards/gloomhaven" ] [ text "Any2Cards" ] +// ] +// ] +// , div [ class "pkg" ] +// [ div +// [ class "copy-wrapper" ] +// [ span [ class "pkgCopy" ] +// [ text "Developed by " +// , a [ href "https://purplekingdomgames.com/" ] [ text "Purple Kingdom Games" ] +// ] +// , div +// [ class "sponsor" ] +// [ iframe +// [ class "sponsor-button" +// , src "https://github.com/sponsors/PurpleKingdomGames/button" +// , title "Sponsor PurpleKingdomGames" +// , attribute "aria-hidden" "true" +// ] +// [] +// ] +// ] +// , div +// [ class "version" ] +// [ a [ target "_new", href "https://github.com/PurpleKingdomGames/virtual-gloomhaven-board/issues/new/choose" ] [ text "Report a bug" ] +// , span [] [ text ("Version " ++ v) ] +// ] +// ] +// ] + +// formatNameString : String -> String +// formatNameString name = +// name +// |> String.split "-" +// |> List.map +// (\s -> +// String.toUpper (String.slice 0 1 s) +// ++ String.slice 1 (String.length s) s +// ) +// |> String.join " " + +// getTutorialHtml : String -> Int -> Msg -> ( String, Html.Html Msg ) +// getTutorialHtml tutorialText stepNo[Msg] = +// ( "tutorial" +// , Dom.element "div" +// |> Dom.addClass "tutorial" +// |> Dom.addClass ("step-" ++ String.fromInt stepNo) +// |> Dom.appendChild +// (Dom.element "div" +// |> Dom.addClass "body" +// |> Dom.appendText tutorialText +// ) +// |> Dom.appendChild +// (Dom.element "div" +// |> Dom.addClass "footer" +// |> Dom.addClass "button-wrapper" +// |> Dom.appendChild +// (Dom.element "button" +// |> Dom.appendText "Got it!" +// |> Dom.addActionStopPropagation ( "click", Msg ) +// ) +// ) +// |> Dom.render +// ) + +} + +enum ContextMenu: + case Open + case Closed + case TwoPlayerSubMenu + case ThreePlayerSubMenu + case FourPlayerSubMenu + case SpawnSubMenu + case SummonSubMenu + case PlaceOverlayMenu + case PlaceTokenMenu + case PlaceHighlightMenu + case AddObstacleSubMenu + case AddTrapSubMenu + +final case class CellModel[Msg]( + overlays: List[BoardOverlay], + pieces: List[Piece], + scenarioMonsters: List[ScenarioMonster], + coords: (Int, Int), + currentDraggable: Option[MoveablePiece], + dragOverlays: Boolean, + dragPieces: Boolean, + dragDoors: Boolean, + dragEvents: DragEvents[Msg], + dropEvents: DropEvents[Msg], + passable: Boolean, + hidden: Boolean +) + +final case class BoardOverlayModel[Msg]( + isDragging: Boolean, + coords: Option[(Int, Int)], + overlay: BoardOverlay, + dragEvents: DragEvents[Msg] +) + +final case class PieceModel[Msg]( + isDragging: Boolean, + coords: Option[(Int, Int)], + piece: Piece, + dragEvents: DragEvents[Msg] +) + +final case class ScenarioMonsterModel[Msg]( + isDragging: Boolean, + coords: Option[(Int, Int)], + monster: ScenarioMonster, + dragEvents: DragEvents[Msg] +) + +final case class DragEvents[Msg]( + moveStart: MoveablePiece => Option[(DragDrop.EffectAllowed, Decode.Value)] => Msg, + moveCancel: Msg, + touchStart: MoveablePiece => Msg, + touchMove: (Float, Float) => Msg, + touchEnd: (Float, Float) => Msg, + noOp: Msg +) + +final case class DropEvents[Msg]( + moveTargetChanged: (Int, Int) => Option[(DragDrop.DropEffect, Decode.Value)] => Msg, + moveCompleted: Msg +) diff --git a/ui/ui/src/vgb/Game.scala b/ui/ui/src/vgb/Game.scala index 11c678c0..b57b837a 100644 --- a/ui/ui/src/vgb/Game.scala +++ b/ui/ui/src/vgb/Game.scala @@ -1,51 +1,46 @@ package vgb -// object Game: +object Game: - // empty : Game - // empty = - // Game emptyState Scenario.empty (Random.initialSeed 0) [] Array.empty + val empty: Game = + Game(emptyState, Scenario.empty, 0, Nil, Nil) + val emptyState: GameState = + GameState((InbuiltScenario(Gloomhaven(1))), Nil, 0, Nil, Nil, Nil, Map.empty, "") - // emptyState : GameState - // emptyState = - // GameState (InbuiltScenario Gloomhaven 1) [] 0 [] [] [] Dict.empty "" + def getPieceType(piece: PieceType): String = + piece match + case Player(_) => + "player" - // getPieceType : PieceType -> String - // getPieceType piece = - // case piece of - // Player _ -> - // "player" + case AI(t) => + t match + case Summons(_) => + "player" - // AI t -> - // case t of - // Summons _ -> - // "player" + case Enemy(_) => + "monster" - // Enemy _ -> - // "monster" + case None => + "" - // None -> - // "" + def getPieceName(piece: PieceType): String = + piece match + case Player(p) => + Character.characterToString(p).getOrElse("") - // getPieceName : PieceType -> String - // getPieceName piece = - // case piece of - // Player p -> - // Maybe.withDefault "" (characterToString p) + case AI(t) => + t match + case Summons(_) => + "summons" - // AI t -> - // case t of - // Summons _ -> - // "summons" + case Enemy(e)=> + Monster.monsterTypeToString(e.monster).getOrElse("") - // Enemy e -> - // Maybe.withDefault "" (monsterTypeToString e.monster) - - // None -> - // "" + case None => + "" // generateGameMap : GameStateScenario -> Scenario -> String -> List CharacterClass -> Seed -> Game @@ -941,7 +936,7 @@ final case class Cell final case class Game ( state : GameState , scenario : Scenario - , seed : Random.Seed + , seed : Long , roomData : List[RoomData] , staticBoard : List[List[Cell]] ) From b88233685b4a757a9d8f80bfbb4f841006d99ee7 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Sun, 9 Apr 2023 16:40:14 +0100 Subject: [PATCH 20/60] Blocking out some functions --- ui/ui/src/vgb/BoardHtml.scala | 434 ++++++++++++++++++++++++++++++++-- 1 file changed, 418 insertions(+), 16 deletions(-) diff --git a/ui/ui/src/vgb/BoardHtml.scala b/ui/ui/src/vgb/BoardHtml.scala index c62d75a6..5c2d5705 100644 --- a/ui/ui/src/vgb/BoardHtml.scala +++ b/ui/ui/src/vgb/BoardHtml.scala @@ -1,5 +1,6 @@ package vgb +import tyrian.Html import tyrian.Html.* object BoardHtml { @@ -25,22 +26,63 @@ object BoardHtml { } ) -// getAllMapTileHtml : List RoomData -> String -> Int -> Int -> Html.Html Msg -// getAllMapTileHtml roomData currentDraggable draggableX draggableY = -// let -// allRooms = -// if List.member currentDraggable (List.map (\r -> Maybe.withDefault "" (refToString r.ref)) roomData) then -// roomData - -// else -// case stringToRef currentDraggable of -// Just r -> -// RoomData r ( draggableX, draggableY ) 0 :: roomData - -// Nothing -> -// roomData -// in -// getMapTileHtml (map (\d -> d.ref) allRooms) allRooms currentDraggable draggableX draggableY + def getAllMapTileHtml(roomData: List[RoomData], currentDraggable: String, draggableX: Int, draggableY: Int): Html[Msg] = { + val allRooms = if (roomData.exists(r => BoardMapTile.refToString(r.ref).contains(currentDraggable))) { + roomData + } else { + BoardMapTile.stringToRef(currentDraggable) match { + case Some(r) => RoomData(r, (draggableX, draggableY), 0) :: roomData + case None => roomData + } + } + getMapTileHtml(allRooms.map(_.ref), allRooms, currentDraggable, draggableX, draggableY) + } + + // getAllMapTileHtml : List RoomData -> String -> Int -> Int -> Html.Html Msg + // getAllMapTileHtml roomData currentDraggable draggableX draggableY = + // let + // allRooms = + // if List.member currentDraggable (List.map (\r -> Maybe.withDefault "" (refToString r.ref)) roomData) then + // roomData + + // else + // case stringToRef currentDraggable of + // Just r -> + // RoomData r ( draggableX, draggableY ) 0 :: roomData + + // Nothing -> + // roomData + // in + // getMapTileHtml (map (\d -> d.ref) allRooms) allRooms currentDraggable draggableX draggableY + + def getSingleMapTileHtml(isVisible: Boolean, ref: String, turns: Int, x: Int, y: Int): Html[Msg] = { + val xPx = x * 76 + (if (y & 1) == 1 then 38 else 0) + val yPx = y * 67 + +
+
+ { +
+
+ { stringToRef(ref) match { + case Some(Empty) => Nil + case Some(r) => + val overlayPrefix = r match { + case J1a => "ja" + case J2a => "ja" + case J1b => "jb" + case J1ba => "jb" + case J1bb => "jb" + case J2b => "jb" + case _ => ref.take(1) + } + { + case None => Nil + } + } +
+
+ } // getSingleMapTileHtml : Bool -> String -> Int -> Int -> Int -> Html.Html Msg // getSingleMapTileHtml isVisible ref turns x y = @@ -372,16 +414,26 @@ object BoardHtml { // e // ) + def getPieceForCoord(x: Int, y: Int, pieces: List[Piece]): Option[Piece] = + pieces.filter(p => p.x == x && p.y == y).headOption + // getPieceForCoord : Int -> Int -> List Piece -> Maybe Piece // getPieceForCoord x y pieces = // List.filter (\p -> p.x == x && p.y == y) pieces // |> List.head + def getScenarioMonsterForCoord(x: Int, y: Int, monsters: List[ScenarioMonster]): Option[ScenarioMonster] = + monsters.filter(m => m.initialX == x && m.initialY == y).headOption + // getScenarioMonsterForCoord : Int -> Int -> List ScenarioMonster -> Maybe ScenarioMonster // getScenarioMonsterForCoord x y monsters = // List.filter (\m -> m.initialX == x && m.initialY == y) monsters // |> List.head + + def filterOverlaysForCoord(x: Int, y: Int, overlay: BoardOverlay): Boolean = + overlay.cells.exists { case (oX, oY) => oX == x && oY == y } + // filterOverlaysForCoord : Int -> Int -> BoardOverlay -> Bool // filterOverlaysForCoord x y overlay = // case List.head (List.filter (\( oX, oY ) -> oX == x && oY == y) overlay.cells) of @@ -391,6 +443,24 @@ object BoardHtml { // Nothing -> // False + def getSortOrderForOverlay(overlay: BoardOverlayType): Int = + overlay match { + case Token(_) => 0 + case Door(_, _) => 1 + case Hazard(_) => 2 + case DifficultTerrain(_) => 3 + case StartingLocation => 4 + case Rift => 5 + case Treasure(t) => t match { + case Chest(_) => 6 + case Coin(_) => 7 + } + case Obstacle(_) => 8 + case Trap(_) => 9 + case Wall(_) => 10 + case Highlight(_) => 11 + } + // getSortOrderForOverlay : BoardOverlayType -> Int // getSortOrderForOverlay overlay = // case overlay of @@ -432,6 +502,113 @@ object BoardHtml { // Highlight _ -> // 11 +// def overlayToHtml(dragOverlays: Boolean, dragDoors: Boolean, model: BoardOverlayModel[Msg]): (String, Dom.Element[Msg]) = { +// val label = getLabelForOverlay(model.overlay, model.coords) +// ( +// label, +// Dom.element("div") +// .addAttribute(attribute("aria-label", label)) +// .addClass("overlay") +// .addClassConditional("being-dragged", model.isDragging) +// .addClass( +// model.overlay.ref match { +// case StartingLocation => "start-location" +// case Rift => "rift" +// case Treasure(t) => +// "treasure " + (t match { +// case Coin(_) => "coin" +// case Chest(_) => "chest" +// }) +// case Obstacle(_) => "obstacle" +// case Hazard(_) => "hazard" +// case Highlight(_) => "highlight" +// case DifficultTerrain(_) => "difficult-terrain" +// case Door(c, _) => +// "door" + (c match { +// case Corridor(_, _) => " corridor" +// case _ => "" +// }) +// case Trap(_) => "trap" +// case Token(_) => "token" +// case Wall(_) => "wall" +// } +// ) +// .addClass( +// model.overlay.direction match { +// case Default => "" +// case Vertical => "vertical" +// case VerticalReverse => "vertical-reverse" +// case Horizontal => "horizontal" +// case DiagonalRight => "diagonal-right" +// case DiagonalLeft => "diagonal-left" +// case DiagonalRightReverse => "diagonal-right-reverse" +// case DiagonalLeftReverse => "diagonal-left-reverse" +// } +// ) +// .addAttributeConditional( +// attribute( +// "data-index", +// model.overlay.ref match { +// case Treasure(t) => t match { +// case Chest(NormalChest(i)) => String.valueOf(i) +// case Goal => "Goal" +// case Locked => "???" +// case _ => "" +// } +// case _ => "" +// } +// ) +// )( +// model.overlay.ref match { +// case Treasure(_) => true +// case _ => false +// } +// ) +// .appendChild( +// model.overlay.ref match { +// case Token(value) => +// Dom.element("span").appendText(value) +// case Highlight(c) => +// Dom.element("div").addStyle("background-color", Colour.toHexString(c)) +// case _ => +// Dom.element("img") +// .addAttribute(alt(getOverlayLabel(model.overlay.ref))) +// .addAttribute(attribute("src", getOverlayImageName(model.overlay, model.coords))) +// .addAttribute(attribute("draggable", "false")) +// } +// ) +// .map( +// model.overlay.ref match { +// case Treasure(Coin(i)) => +// _.appendChild( +// Dom.element("span").appendText(String.valueOf(i)) +// ) +// case _ => identity +// } +// ) +// .map( +// if (dragOverlays) { +// model.overlay.ref match { +// case Treasure(Coin(_)) => +// if (model.coords.isEmpty) { +// makeDraggable(OverlayType(model.overlay, None), model.coords, model.dragEvents) +// } else { +// _.addAttribute(attribute("draggable", "false")) +// } +// case Treasure(Chest(_)) => +// _.addAttribute(attribute("draggable", "false")) +// case Highlight(_) => +// _.addAttribute(attribute("draggable", "false")) +// case Door(_, _) => +// if (dragDoors) { +// identity +// } else { +// _.addAttribute(attribute("draggable", "false")) +// } +// case _ => +// makeDraggable(OverlayType(model.overlay, None), model.coords, model + + // overlayToHtml : Bool -> Bool -> BoardOverlayModel Msg -> ( String, Dom.Element Msg ) // overlayToHtml dragOverlays dragDoors model = // let @@ -620,6 +797,54 @@ object BoardHtml { // ) // ) + def pieceToHtml(dragPiece: Boolean, model: PieceModel[Msg]): (String, dom.Element[Msg]) = { + def playerHtml(l: String, p: String, e: dom.Element[Msg]): dom.Element[Msg] = { + e.addClass("hex-mask").appendChild( + dom.html("img") + .setAttribute("alt", l) + .setAttribute("src", s"/img/characters/portraits/$p.png") + ) + } + + val label = getLabelForPiece(model.piece) + val element = dom.html("div") + .setAttribute("aria-label", model.coords match { + case Some((x, y)) => s"$label at $x, $y" + case None => s"Add New $label" + }) + .addClass(getPieceType(model.piece.ref)) + .addClass(getPieceName(model.piece.ref)) + .addClassConditional("being-dragged", model.isDragging) + .appendChild(model.piece.ref match { + case Player(p) => + playerHtml(label, characterToString.getOrElse(p, ""), dom.html("div")) + case AI(Enemy(m)) => + enemyToHtml(m, label) + case AI(Summons(NormalSummons(i, colour))) => + dom.html("div") + .appendChildList(Seq( + dom.html("img") + .setAttribute("alt", label) + .setAttribute("src", "/img/characters/summons.png") + .setAttribute("draggable", "false"), + dom.html("span").setTextContent(i.toString) + )) + case AI(Summons(BearSummons)) => + playerHtml(label, "bear", dom.html("div").addClass("bear")) + case Game.None => + dom.html("div").addClass("none") + }) + + if (dragPiece) { + makeDraggable(PieceType(model.piece), model.coords, model.dragEvents)(element) + } else { + element + } + + (label, element) + } + + // pieceToHtml : Bool -> PieceModel Msg -> ( String, Dom.Element Msg ) // pieceToHtml dragPiece model = // let @@ -684,6 +909,31 @@ object BoardHtml { // ) // ) + def scenarioMonsterToHtml(dragPiece: Boolean, model: ScenarioMonsterModel[Msg]): (String, Dom.Element[Msg]) = { + val monster = model.monster + val label = monster.monster.monster.map(monsterTypeToString).getOrElse("").replace("-", " ") + val pieceModel = PieceModel(ref = AI(Enemy(monster.monster)), x = monster.initialX, y = monster.initialY) + val ariaLabel = model.coords match { + case Some((x, y)) => s"$label at $x, $y" + case None => s"Add New $label" + } + + (label, + Dom + .element("div") + .addAttribute(attribute("aria-label", ariaLabel)) + .addClass("monster") + .addClass(monster.monster.monster.map(monsterTypeToString).getOrElse("")) + .addClassConditional("being-dragged", model.isDragging) + .appendChild(enemyToHtml(monster.monster, label)) + .appendChild(scenarioMonsterVisibilityToHtml(monster.twoPlayer).addClass("two-player")) + .appendChild(scenarioMonsterVisibilityToHtml(monster.threePlayer).addClass("three-player")) + .appendChild(scenarioMonsterVisibilityToHtml(monster.fourPlayer).addClass("four-player")) + .map(if (dragPiece) makeDraggable(PieceType(pieceModel), model.coords, model.dragEvents) else identity) + ) + } + + // scenarioMonsterToHtml : Bool -> ScenarioMonsterModel Msg -> ( String, Dom.Element Msg ) // scenarioMonsterToHtml dragPiece model = // let @@ -736,6 +986,17 @@ object BoardHtml { // ) // ) + def cellValueToString(passable: Boolean, hidden: Boolean): String = { + if (hidden) { + "hidden" + } else if (passable) { + "passable" + } else { + "impassable" + } + } + + // cellValueToString : Bool -> Bool -> String // cellValueToString passable hidden = // if hidden then @@ -747,6 +1008,12 @@ object BoardHtml { // else // "impassable" + def getLabelForOverlay(overlay: BoardOverlay, coords: Option[(Int, Int)]): String = coords match { + case Some((x, y)) => s"${getOverlayLabel(overlay.ref)} at $x, $y" + case None => s"Add new ${getOverlayLabel(overlay.ref)}" + } + + // getLabelForOverlay : BoardOverlay -> Maybe ( Int, Int ) -> String // getLabelForOverlay overlay coords = // case coords of @@ -756,6 +1023,42 @@ object BoardHtml { // Nothing -> // "Add new " ++ getOverlayLabel overlay.ref + def getLabelForPiece(piece: Piece): String = { + piece.ref match { + case Player(p) => + characterToString(p) + .getOrElse("") + .replace("-", " ") + + case AI(t) => + t match { + case Enemy(m) => + (m.monster match { + case NormalType(_) => + m.level match { + case Elite => "Elite" + case Normal => "Normal" + case _ => "" + } + case BossType(_) => "Boss" + }) + " " + + monsterTypeToString(m.monster) + .getOrElse("") + .replace("-", " ") + + (if (m.id > 0) " (" + m.id.toString + ")" else "") + + case Summons(NormalSummons(i, _)) => + "Summons Number " + i.toString + + case Summons(BearSummons) => + "Beast Tyrant Bear Summons" + } + + case Game.None => "None" + } + } + + // getLabelForPiece : Piece -> String // getLabelForPiece piece = // case piece.ref of @@ -801,6 +1104,32 @@ object BoardHtml { // Game.None -> // "None" + def getOverlayImageName(overlay: BoardOverlay, coords: Option[(Int, Int)]): String = { + val path = "/img/overlays/" + val overlayName = getBoardOverlayName(overlay.ref).getOrElse("") + val extension = ".png" + val extendedOverlayName = overlay.direction match { + case Vertical | VerticalReverse => + overlay.ref match { + case Door(Stone, _) => "-vert" + case Door(BreakableWall, _) => "-vert" + case Door(Wooden, _) => "-vert" + case Obstacle(Altar) => "-vert" + case _ => "" + } + case _ => "" + } + val segmentPart = coords match { + case Some((x, y)) => + toIndexedList(overlay.cells) + .collectFirst { case (segment, (oX, oY)) if oX == x && oY == y => segment } + .map(segment => if (segment > 0) s"-${segment + 1}" else "") + .getOrElse("") + case None => "" + } + path + overlayName + extendedOverlayName + segmentPart + extension + } + // getOverlayImageName : BoardOverlay -> Maybe ( Int, Int ) -> String // getOverlayImageName overlay coords = // let @@ -853,6 +1182,33 @@ object BoardHtml { // in // path ++ overlayName ++ extendedOverlayName ++ segmentPart ++ extension + def enemyToHtml(monster: Monster, altText: String, element: dom.Element): dom.Element = { + val cssClass: String = monster.monster match { + case NormalType(_) => monster.level match { + case Elite => "elite" + case Normal => "normal" + case Monster.None => "" + } + case BossType(_) => "boss" + } + + element + .classList.add(cssClass) + .classList.add("hex-mask") + .appendChild( + List( + dom.document.createElement("img") + .setAttribute("src", s"/img/monsters/${monsterTypeToString(monster.monster).getOrElse("")}.png") + .setAttribute("alt", altText), + dom.document.createElement("span") + .appendChild(dom.document.createTextNode( + if (monster.id == 0) "" else monster.id.toString + )) + ): _* + ) + } + + // enemyToHtml : Monster -> String -> Element Msg -> Element Msg // enemyToHtml monster altText element = // let @@ -895,6 +1251,16 @@ object BoardHtml { // ) // ] +def scenarioMonsterVisibilityToHtml(level: MonsterLevel): Element[Msg] = + Dom.element("div") + .addClass("monster-visibility") + .addClass(level match { + case Normal => "normal" + case Elite => "elite" + case Monster.None => "none" + }) + + // scenarioMonsterVisibilityToHtml : MonsterLevel -> Element Msg // scenarioMonsterVisibilityToHtml level = // Dom.element "div" @@ -1000,6 +1366,13 @@ object BoardHtml { // ] // ] + def formatNameString(name: String): String = { + name + .split("-") + .map(s => s.slice(0, 1).toUpperCase + s.slice(1)) + .mkString(" ") + } + // formatNameString : String -> String // formatNameString name = // name @@ -1011,6 +1384,35 @@ object BoardHtml { // ) // |> String.join " " + def getTutorialHtml(tutorialText: String, stepNo: Int)(msg: Msg): (String, Html[Msg]) = { + ("tutorial", + Dom + .element("div") + .addClass("tutorial") + .addClass(s"step-$stepNo") + .appendChild( + Dom + .element("div") + .addClass("body") + .appendText(tutorialText) + ) + .appendChild( + Dom + .element("div") + .addClass("footer") + .addClass("button-wrapper") + .appendChild( + Dom + .element("button") + .appendText("Got it!") + .addActionStopPropagation("click", msg) + ) + ) + .render + ) + } + + // getTutorialHtml : String -> Int -> Msg -> ( String, Html.Html Msg ) // getTutorialHtml tutorialText stepNo[Msg] = // ( "tutorial" From 081c86859ca5551f27ace10f2b3ea02a9d29cc87 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 10 Apr 2023 08:47:43 +0100 Subject: [PATCH 21/60] No compile errors, lots missing --- ui/ui/src/vgb/AppStorage.scala | 63 ++ ui/ui/src/vgb/BoardHtml.scala | 568 +++++----- ui/ui/src/vgb/Game.scala | 1861 ++++++++++++++++---------------- 3 files changed, 1252 insertions(+), 1240 deletions(-) create mode 100644 ui/ui/src/vgb/AppStorage.scala diff --git a/ui/ui/src/vgb/AppStorage.scala b/ui/ui/src/vgb/AppStorage.scala new file mode 100644 index 00000000..380b2d98 --- /dev/null +++ b/ui/ui/src/vgb/AppStorage.scala @@ -0,0 +1,63 @@ +package vgb + +object AppStorage: + + val defaultSummonsColour: String = "#963f9d" + +final case class StoredData(config: Config, gameState: GameState) + +final case class Config( + appMode: AppModeType, + gameMode: GameModeType, + roomCode: Option[String], + summonsColour: String, + showRoomCode: Boolean, + envelopeX: Boolean, + boardOnly: Boolean, + campaignTracker: Option[CampaignTrackerUrl], + tutorialStep: Int +) + +final case class MapData( + scenarioTitle: String, + roomData: List[ExtendedRoomData], + overlays: List[BoardOverlay], + monsters: List[ScenarioMonster] +) + +final case class ExtendedRoomData(data: RoomData, rotationPoint: (Int, Int)) + +final case class AppOverrides( + initScenario: Option[Int], + initPlayers: Option[List[CharacterClass]], + initRoomCodeSeed: Option[Int], + lockScenario: Boolean, + lockPlayers: Boolean, + lockRoomCode: Boolean, + campaignTracker: Option[CampaignTrackerUrl] +) + +enum CampaignTrackerUrl: + case CampaignTrackerUrl(name: String, url: String) + +enum GameModeType: + case MovePiece + case KillPiece + case MoveOverlay + case DestroyOverlay + case LootCell + case RevealRoom + case AddPiece + +enum AppModeType: + case Game + case ScenarioDialog + case ConfigDialog + case PlayerChoiceDialog + +final case class MoveablePiece(ref: MoveablePieceType, coords: Option[(Int, Int)], target: Option[(Int, Int)]) + +enum MoveablePieceType: + case OverlayType(overlay: BoardOverlay, position: Option[(Int, Int)]) + case PieceType(typ: Piece) + case RoomType(room: RoomData) diff --git a/ui/ui/src/vgb/BoardHtml.scala b/ui/ui/src/vgb/BoardHtml.scala index 5c2d5705..481c918d 100644 --- a/ui/ui/src/vgb/BoardHtml.scala +++ b/ui/ui/src/vgb/BoardHtml.scala @@ -5,38 +5,38 @@ import tyrian.Html.* object BoardHtml { - def getMapTileHtml( - visibleRooms: List[MapTileRef], - roomData: List[RoomData], - currentDraggable: String, - draggableX: Int, - draggableY: Int - ): Html[Msg] = - div(`class` := "mapTiles")( - roomData - .distinctBy(d => BoardMapTile.refToString(d.ref).getOrElse("")) - .map { r => - val isVisible = visibleRooms.contains(r.ref) - val ref = BoardMapTile.refToString(r.ref).getOrElse("") - val (x, y) = - if ref == currentDraggable then (draggableX, draggableY) - else r.origin - - getSingleMapTileHtml(isVisible, ref, r.turns, x, y) - } - ) - - def getAllMapTileHtml(roomData: List[RoomData], currentDraggable: String, draggableX: Int, draggableY: Int): Html[Msg] = { - val allRooms = if (roomData.exists(r => BoardMapTile.refToString(r.ref).contains(currentDraggable))) { - roomData - } else { - BoardMapTile.stringToRef(currentDraggable) match { - case Some(r) => RoomData(r, (draggableX, draggableY), 0) :: roomData - case None => roomData - } - } - getMapTileHtml(allRooms.map(_.ref), allRooms, currentDraggable, draggableX, draggableY) - } + // def getMapTileHtml( + // visibleRooms: List[MapTileRef], + // roomData: List[RoomData], + // currentDraggable: String, + // draggableX: Int, + // draggableY: Int + // ): Html[Msg] = + // div(`class` := "mapTiles")( + // roomData + // .distinctBy(d => BoardMapTile.refToString(d.ref).getOrElse("")) + // .map { r => + // val isVisible = visibleRooms.contains(r.ref) + // val ref = BoardMapTile.refToString(r.ref).getOrElse("") + // val (x, y) = + // if ref == currentDraggable then (draggableX, draggableY) + // else r.origin + + // getSingleMapTileHtml(isVisible, ref, r.turns, x, y) + // } + // ) + + // def getAllMapTileHtml(roomData: List[RoomData], currentDraggable: String, draggableX: Int, draggableY: Int): Html[Msg] = { + // val allRooms = if (roomData.exists(r => BoardMapTile.refToString(r.ref).contains(currentDraggable))) { + // roomData + // } else { + // BoardMapTile.stringToRef(currentDraggable) match { + // case Some(r) => RoomData(r, (draggableX, draggableY), 0) :: roomData + // case None => roomData + // } + // } + // getMapTileHtml(allRooms.map(_.ref), allRooms, currentDraggable, draggableX, draggableY) + // } // getAllMapTileHtml : List RoomData -> String -> Int -> Int -> Html.Html Msg // getAllMapTileHtml roomData currentDraggable draggableX draggableY = @@ -55,34 +55,34 @@ object BoardHtml { // in // getMapTileHtml (map (\d -> d.ref) allRooms) allRooms currentDraggable draggableX draggableY - def getSingleMapTileHtml(isVisible: Boolean, ref: String, turns: Int, x: Int, y: Int): Html[Msg] = { - val xPx = x * 76 + (if (y & 1) == 1 then 38 else 0) - val yPx = y * 67 - -
-
- { -
-
- { stringToRef(ref) match { - case Some(Empty) => Nil - case Some(r) => - val overlayPrefix = r match { - case J1a => "ja" - case J2a => "ja" - case J1b => "jb" - case J1ba => "jb" - case J1bb => "jb" - case J2b => "jb" - case _ => ref.take(1) - } - { - case None => Nil - } - } -
-
- } + // def getSingleMapTileHtml(isVisible: Boolean, ref: String, turns: Int, x: Int, y: Int): Html[Msg] = { + // val xPx = x * 76 + (if (y & 1) == 1 then 38 else 0) + // val yPx = y * 67 + + //
+ //
+ // { + //
+ //
+ // { stringToRef(ref) match { + // case Some(Empty) => Nil + // case Some(r) => + // val overlayPrefix = r match { + // case J1a => "ja" + // case J2a => "ja" + // case J1b => "jb" + // case J1ba => "jb" + // case J1bb => "jb" + // case J2b => "jb" + // case _ => ref.take(1) + // } + // { + // case None => Nil + // } + // } + //
+ //
+ // } // getSingleMapTileHtml : Bool -> String -> Int -> Int -> Int -> Html.Html Msg // getSingleMapTileHtml isVisible ref turns x y = @@ -424,13 +424,11 @@ object BoardHtml { def getScenarioMonsterForCoord(x: Int, y: Int, monsters: List[ScenarioMonster]): Option[ScenarioMonster] = monsters.filter(m => m.initialX == x && m.initialY == y).headOption - // getScenarioMonsterForCoord : Int -> Int -> List ScenarioMonster -> Maybe ScenarioMonster // getScenarioMonsterForCoord x y monsters = // List.filter (\m -> m.initialX == x && m.initialY == y) monsters // |> List.head - def filterOverlaysForCoord(x: Int, y: Int, overlay: BoardOverlay): Boolean = overlay.cells.exists { case (oX, oY) => oX == x && oY == y } @@ -443,23 +441,23 @@ object BoardHtml { // Nothing -> // False - def getSortOrderForOverlay(overlay: BoardOverlayType): Int = - overlay match { - case Token(_) => 0 - case Door(_, _) => 1 - case Hazard(_) => 2 - case DifficultTerrain(_) => 3 - case StartingLocation => 4 - case Rift => 5 - case Treasure(t) => t match { - case Chest(_) => 6 - case Coin(_) => 7 - } - case Obstacle(_) => 8 - case Trap(_) => 9 - case Wall(_) => 10 - case Highlight(_) => 11 - } + // def getSortOrderForOverlay(overlay: BoardOverlayType): Int = + // overlay match { + // case Token(_) => 0 + // case Door(_, _) => 1 + // case Hazard(_) => 2 + // case DifficultTerrain(_) => 3 + // case StartingLocation => 4 + // case Rift => 5 + // case Treasure(t) => t match { + // case Chest(_) => 6 + // case Coin(_) => 7 + // } + // case Obstacle(_) => 8 + // case Trap(_) => 9 + // case Wall(_) => 10 + // case Highlight(_) => 11 + // } // getSortOrderForOverlay : BoardOverlayType -> Int // getSortOrderForOverlay overlay = @@ -608,7 +606,6 @@ object BoardHtml { // case _ => // makeDraggable(OverlayType(model.overlay, None), model.coords, model - // overlayToHtml : Bool -> Bool -> BoardOverlayModel Msg -> ( String, Dom.Element Msg ) // overlayToHtml dragOverlays dragDoors model = // let @@ -797,53 +794,52 @@ object BoardHtml { // ) // ) - def pieceToHtml(dragPiece: Boolean, model: PieceModel[Msg]): (String, dom.Element[Msg]) = { - def playerHtml(l: String, p: String, e: dom.Element[Msg]): dom.Element[Msg] = { - e.addClass("hex-mask").appendChild( - dom.html("img") - .setAttribute("alt", l) - .setAttribute("src", s"/img/characters/portraits/$p.png") - ) - } - - val label = getLabelForPiece(model.piece) - val element = dom.html("div") - .setAttribute("aria-label", model.coords match { - case Some((x, y)) => s"$label at $x, $y" - case None => s"Add New $label" - }) - .addClass(getPieceType(model.piece.ref)) - .addClass(getPieceName(model.piece.ref)) - .addClassConditional("being-dragged", model.isDragging) - .appendChild(model.piece.ref match { - case Player(p) => - playerHtml(label, characterToString.getOrElse(p, ""), dom.html("div")) - case AI(Enemy(m)) => - enemyToHtml(m, label) - case AI(Summons(NormalSummons(i, colour))) => - dom.html("div") - .appendChildList(Seq( - dom.html("img") - .setAttribute("alt", label) - .setAttribute("src", "/img/characters/summons.png") - .setAttribute("draggable", "false"), - dom.html("span").setTextContent(i.toString) - )) - case AI(Summons(BearSummons)) => - playerHtml(label, "bear", dom.html("div").addClass("bear")) - case Game.None => - dom.html("div").addClass("none") - }) - - if (dragPiece) { - makeDraggable(PieceType(model.piece), model.coords, model.dragEvents)(element) - } else { - element - } - - (label, element) - } - + // def pieceToHtml(dragPiece: Boolean, model: PieceModel[Msg]): (String, dom.Element[Msg]) = { + // def playerHtml(l: String, p: String, e: dom.Element[Msg]): dom.Element[Msg] = { + // e.addClass("hex-mask").appendChild( + // dom.html("img") + // .setAttribute("alt", l) + // .setAttribute("src", s"/img/characters/portraits/$p.png") + // ) + // } + + // val label = getLabelForPiece(model.piece) + // val element = dom.html("div") + // .setAttribute("aria-label", model.coords match { + // case Some((x, y)) => s"$label at $x, $y" + // case None => s"Add New $label" + // }) + // .addClass(getPieceType(model.piece.ref)) + // .addClass(getPieceName(model.piece.ref)) + // .addClassConditional("being-dragged", model.isDragging) + // .appendChild(model.piece.ref match { + // case Player(p) => + // playerHtml(label, characterToString.getOrElse(p, ""), dom.html("div")) + // case AI(Enemy(m)) => + // enemyToHtml(m, label) + // case AI(Summons(NormalSummons(i, colour))) => + // dom.html("div") + // .appendChildList(Seq( + // dom.html("img") + // .setAttribute("alt", label) + // .setAttribute("src", "/img/characters/summons.png") + // .setAttribute("draggable", "false"), + // dom.html("span").setTextContent(i.toString) + // )) + // case AI(Summons(BearSummons)) => + // playerHtml(label, "bear", dom.html("div").addClass("bear")) + // case Game.None => + // dom.html("div").addClass("none") + // }) + + // if (dragPiece) { + // makeDraggable(PieceType(model.piece), model.coords, model.dragEvents)(element) + // } else { + // element + // } + + // (label, element) + // } // pieceToHtml : Bool -> PieceModel Msg -> ( String, Dom.Element Msg ) // pieceToHtml dragPiece model = @@ -909,30 +905,29 @@ object BoardHtml { // ) // ) - def scenarioMonsterToHtml(dragPiece: Boolean, model: ScenarioMonsterModel[Msg]): (String, Dom.Element[Msg]) = { - val monster = model.monster - val label = monster.monster.monster.map(monsterTypeToString).getOrElse("").replace("-", " ") - val pieceModel = PieceModel(ref = AI(Enemy(monster.monster)), x = monster.initialX, y = monster.initialY) - val ariaLabel = model.coords match { - case Some((x, y)) => s"$label at $x, $y" - case None => s"Add New $label" - } - - (label, - Dom - .element("div") - .addAttribute(attribute("aria-label", ariaLabel)) - .addClass("monster") - .addClass(monster.monster.monster.map(monsterTypeToString).getOrElse("")) - .addClassConditional("being-dragged", model.isDragging) - .appendChild(enemyToHtml(monster.monster, label)) - .appendChild(scenarioMonsterVisibilityToHtml(monster.twoPlayer).addClass("two-player")) - .appendChild(scenarioMonsterVisibilityToHtml(monster.threePlayer).addClass("three-player")) - .appendChild(scenarioMonsterVisibilityToHtml(monster.fourPlayer).addClass("four-player")) - .map(if (dragPiece) makeDraggable(PieceType(pieceModel), model.coords, model.dragEvents) else identity) - ) - } - + // def scenarioMonsterToHtml(dragPiece: Boolean, model: ScenarioMonsterModel[Msg]): (String, Dom.Element[Msg]) = { + // val monster = model.monster + // val label = monster.monster.monster.map(monsterTypeToString).getOrElse("").replace("-", " ") + // val pieceModel = PieceModel(ref = AI(Enemy(monster.monster)), x = monster.initialX, y = monster.initialY) + // val ariaLabel = model.coords match { + // case Some((x, y)) => s"$label at $x, $y" + // case None => s"Add New $label" + // } + + // (label, + // Dom + // .element("div") + // .addAttribute(attribute("aria-label", ariaLabel)) + // .addClass("monster") + // .addClass(monster.monster.monster.map(monsterTypeToString).getOrElse("")) + // .addClassConditional("being-dragged", model.isDragging) + // .appendChild(enemyToHtml(monster.monster, label)) + // .appendChild(scenarioMonsterVisibilityToHtml(monster.twoPlayer).addClass("two-player")) + // .appendChild(scenarioMonsterVisibilityToHtml(monster.threePlayer).addClass("three-player")) + // .appendChild(scenarioMonsterVisibilityToHtml(monster.fourPlayer).addClass("four-player")) + // .map(if (dragPiece) makeDraggable(PieceType(pieceModel), model.coords, model.dragEvents) else identity) + // ) + // } // scenarioMonsterToHtml : Bool -> ScenarioMonsterModel Msg -> ( String, Dom.Element Msg ) // scenarioMonsterToHtml dragPiece model = @@ -986,7 +981,7 @@ object BoardHtml { // ) // ) - def cellValueToString(passable: Boolean, hidden: Boolean): String = { + def cellValueToString(passable: Boolean, hidden: Boolean): String = if (hidden) { "hidden" } else if (passable) { @@ -994,8 +989,6 @@ object BoardHtml { } else { "impassable" } - } - // cellValueToString : Bool -> Bool -> String // cellValueToString passable hidden = @@ -1008,11 +1001,10 @@ object BoardHtml { // else // "impassable" - def getLabelForOverlay(overlay: BoardOverlay, coords: Option[(Int, Int)]): String = coords match { - case Some((x, y)) => s"${getOverlayLabel(overlay.ref)} at $x, $y" - case None => s"Add new ${getOverlayLabel(overlay.ref)}" - } - + // def getLabelForOverlay(overlay: BoardOverlay, coords: Option[(Int, Int)]): String = coords match { + // case Some((x, y)) => s"${getOverlayLabel(overlay.ref)} at $x, $y" + // case None => s"Add new ${getOverlayLabel(overlay.ref)}" + // } // getLabelForOverlay : BoardOverlay -> Maybe ( Int, Int ) -> String // getLabelForOverlay overlay coords = @@ -1023,41 +1015,40 @@ object BoardHtml { // Nothing -> // "Add new " ++ getOverlayLabel overlay.ref - def getLabelForPiece(piece: Piece): String = { - piece.ref match { - case Player(p) => - characterToString(p) - .getOrElse("") - .replace("-", " ") - - case AI(t) => - t match { - case Enemy(m) => - (m.monster match { - case NormalType(_) => - m.level match { - case Elite => "Elite" - case Normal => "Normal" - case _ => "" - } - case BossType(_) => "Boss" - }) + " " + - monsterTypeToString(m.monster) - .getOrElse("") - .replace("-", " ") + - (if (m.id > 0) " (" + m.id.toString + ")" else "") - - case Summons(NormalSummons(i, _)) => - "Summons Number " + i.toString - - case Summons(BearSummons) => - "Beast Tyrant Bear Summons" - } - - case Game.None => "None" - } - } - + // def getLabelForPiece(piece: Piece): String = { + // piece.ref match { + // case Player(p) => + // characterToString(p) + // .getOrElse("") + // .replace("-", " ") + + // case AI(t) => + // t match { + // case Enemy(m) => + // (m.monster match { + // case NormalType(_) => + // m.level match { + // case Elite => "Elite" + // case Normal => "Normal" + // case _ => "" + // } + // case BossType(_) => "Boss" + // }) + " " + + // monsterTypeToString(m.monster) + // .getOrElse("") + // .replace("-", " ") + + // (if (m.id > 0) " (" + m.id.toString + ")" else "") + + // case Summons(NormalSummons(i, _)) => + // "Summons Number " + i.toString + + // case Summons(BearSummons) => + // "Beast Tyrant Bear Summons" + // } + + // case Game.None => "None" + // } + // } // getLabelForPiece : Piece -> String // getLabelForPiece piece = @@ -1104,31 +1095,31 @@ object BoardHtml { // Game.None -> // "None" - def getOverlayImageName(overlay: BoardOverlay, coords: Option[(Int, Int)]): String = { - val path = "/img/overlays/" - val overlayName = getBoardOverlayName(overlay.ref).getOrElse("") - val extension = ".png" - val extendedOverlayName = overlay.direction match { - case Vertical | VerticalReverse => - overlay.ref match { - case Door(Stone, _) => "-vert" - case Door(BreakableWall, _) => "-vert" - case Door(Wooden, _) => "-vert" - case Obstacle(Altar) => "-vert" - case _ => "" - } - case _ => "" - } - val segmentPart = coords match { - case Some((x, y)) => - toIndexedList(overlay.cells) - .collectFirst { case (segment, (oX, oY)) if oX == x && oY == y => segment } - .map(segment => if (segment > 0) s"-${segment + 1}" else "") - .getOrElse("") - case None => "" - } - path + overlayName + extendedOverlayName + segmentPart + extension - } + // def getOverlayImageName(overlay: BoardOverlay, coords: Option[(Int, Int)]): String = { + // val path = "/img/overlays/" + // val overlayName = getBoardOverlayName(overlay.ref).getOrElse("") + // val extension = ".png" + // val extendedOverlayName = overlay.direction match { + // case Vertical | VerticalReverse => + // overlay.ref match { + // case Door(Stone, _) => "-vert" + // case Door(BreakableWall, _) => "-vert" + // case Door(Wooden, _) => "-vert" + // case Obstacle(Altar) => "-vert" + // case _ => "" + // } + // case _ => "" + // } + // val segmentPart = coords match { + // case Some((x, y)) => + // toIndexedList(overlay.cells) + // .collectFirst { case (segment, (oX, oY)) if oX == x && oY == y => segment } + // .map(segment => if (segment > 0) s"-${segment + 1}" else "") + // .getOrElse("") + // case None => "" + // } + // path + overlayName + extendedOverlayName + segmentPart + extension + // } // getOverlayImageName : BoardOverlay -> Maybe ( Int, Int ) -> String // getOverlayImageName overlay coords = @@ -1182,32 +1173,31 @@ object BoardHtml { // in // path ++ overlayName ++ extendedOverlayName ++ segmentPart ++ extension - def enemyToHtml(monster: Monster, altText: String, element: dom.Element): dom.Element = { - val cssClass: String = monster.monster match { - case NormalType(_) => monster.level match { - case Elite => "elite" - case Normal => "normal" - case Monster.None => "" - } - case BossType(_) => "boss" - } - - element - .classList.add(cssClass) - .classList.add("hex-mask") - .appendChild( - List( - dom.document.createElement("img") - .setAttribute("src", s"/img/monsters/${monsterTypeToString(monster.monster).getOrElse("")}.png") - .setAttribute("alt", altText), - dom.document.createElement("span") - .appendChild(dom.document.createTextNode( - if (monster.id == 0) "" else monster.id.toString - )) - ): _* - ) - } - + // def enemyToHtml(monster: Monster, altText: String, element: dom.Element): dom.Element = { + // val cssClass: String = monster.monster match { + // case NormalType(_) => monster.level match { + // case Elite => "elite" + // case Normal => "normal" + // case Monster.None => "" + // } + // case BossType(_) => "boss" + // } + + // element + // .classList.add(cssClass) + // .classList.add("hex-mask") + // .appendChild( + // List( + // dom.document.createElement("img") + // .setAttribute("src", s"/img/monsters/${monsterTypeToString(monster.monster).getOrElse("")}.png") + // .setAttribute("alt", altText), + // dom.document.createElement("span") + // .appendChild(dom.document.createTextNode( + // if (monster.id == 0) "" else monster.id.toString + // )) + // ): _* + // ) + // } // enemyToHtml : Monster -> String -> Element Msg -> Element Msg // enemyToHtml monster altText element = @@ -1251,15 +1241,14 @@ object BoardHtml { // ) // ] -def scenarioMonsterVisibilityToHtml(level: MonsterLevel): Element[Msg] = - Dom.element("div") - .addClass("monster-visibility") - .addClass(level match { - case Normal => "normal" - case Elite => "elite" - case Monster.None => "none" - }) - +// def scenarioMonsterVisibilityToHtml(level: MonsterLevel): Element[Msg] = +// Dom.element("div") +// .addClass("monster-visibility") +// .addClass(level match { +// case Normal => "normal" +// case Elite => "elite" +// case Monster.None => "none" +// }) // scenarioMonsterVisibilityToHtml : MonsterLevel -> Element Msg // scenarioMonsterVisibilityToHtml level = @@ -1366,12 +1355,12 @@ def scenarioMonsterVisibilityToHtml(level: MonsterLevel): Element[Msg] = // ] // ] - def formatNameString(name: String): String = { - name - .split("-") - .map(s => s.slice(0, 1).toUpperCase + s.slice(1)) - .mkString(" ") - } + // def formatNameString(name: String): String = { + // name + // .split("-") + // .map(s => s.slice(0, 1).toUpperCase + s.slice(1)) + // .mkString(" ") + // } // formatNameString : String -> String // formatNameString name = @@ -1384,34 +1373,33 @@ def scenarioMonsterVisibilityToHtml(level: MonsterLevel): Element[Msg] = // ) // |> String.join " " - def getTutorialHtml(tutorialText: String, stepNo: Int)(msg: Msg): (String, Html[Msg]) = { - ("tutorial", - Dom - .element("div") - .addClass("tutorial") - .addClass(s"step-$stepNo") - .appendChild( - Dom - .element("div") - .addClass("body") - .appendText(tutorialText) - ) - .appendChild( - Dom - .element("div") - .addClass("footer") - .addClass("button-wrapper") - .appendChild( - Dom - .element("button") - .appendText("Got it!") - .addActionStopPropagation("click", msg) - ) - ) - .render - ) - } - + // def getTutorialHtml(tutorialText: String, stepNo: Int)(msg: Msg): (String, Html[Msg]) = { + // ("tutorial", + // Dom + // .element("div") + // .addClass("tutorial") + // .addClass(s"step-$stepNo") + // .appendChild( + // Dom + // .element("div") + // .addClass("body") + // .appendText(tutorialText) + // ) + // .appendChild( + // Dom + // .element("div") + // .addClass("footer") + // .addClass("button-wrapper") + // .appendChild( + // Dom + // .element("button") + // .appendText("Got it!") + // .addActionStopPropagation("click", msg) + // ) + // ) + // .render + // ) + // } // getTutorialHtml : String -> Int -> Msg -> ( String, Html.Html Msg ) // getTutorialHtml tutorialText stepNo[Msg] = @@ -1490,7 +1478,7 @@ final case class ScenarioMonsterModel[Msg]( ) final case class DragEvents[Msg]( - moveStart: MoveablePiece => Option[(DragDrop.EffectAllowed, Decode.Value)] => Msg, + moveStart: String, // MoveablePiece => Option[(DragDrop.EffectAllowed, Decode.Value)] => Msg, moveCancel: Msg, touchStart: MoveablePiece => Msg, touchMove: (Float, Float) => Msg, @@ -1499,6 +1487,6 @@ final case class DragEvents[Msg]( ) final case class DropEvents[Msg]( - moveTargetChanged: (Int, Int) => Option[(DragDrop.DropEffect, Decode.Value)] => Msg, + moveTargetChanged: (Int, Int), // => Option[(DragDrop.DropEffect, Decode.Value)] => Msg, moveCompleted: Msg ) diff --git a/ui/ui/src/vgb/Game.scala b/ui/ui/src/vgb/Game.scala index b57b837a..0c51cef4 100644 --- a/ui/ui/src/vgb/Game.scala +++ b/ui/ui/src/vgb/Game.scala @@ -3,965 +3,926 @@ package vgb object Game: val empty: Game = - Game(emptyState, Scenario.empty, 0, Nil, Nil) + Game(emptyState, Scenario.empty, 0, Nil, Nil) val emptyState: GameState = - GameState((InbuiltScenario(Gloomhaven(1))), Nil, 0, Nil, Nil, Nil, Map.empty, "") - - - def getPieceType(piece: PieceType): String = - piece match - case Player(_) => - "player" - - case AI(t) => - t match - case Summons(_) => - "player" - - case Enemy(_) => - "monster" - - case None => - "" - - - def getPieceName(piece: PieceType): String = - piece match - case Player(p) => - Character.characterToString(p).getOrElse("") - - case AI(t) => - t match - case Summons(_) => - "summons" - - case Enemy(e)=> - Monster.monsterTypeToString(e.monster).getOrElse("") - - case None => - "" - - - // generateGameMap : GameStateScenario -> Scenario -> String -> List CharacterClass -> Seed -> Game - // generateGameMap gameStateScenario scenario roomCode players seed = - // let - // ( mapTiles, bounds ) = - // mapTileDataToList scenario.mapTilesData Nothing - - // availableMonsters = - // map (\m -> ( Maybe.withDefault "" (monsterTypeToString m), initialize (getMonsterBucketSize m) identity )) scenario.additionalMonsters - // |> filter (\( k, _ ) -> k /= "") - // |> map (\( k, v ) -> ( k, Tuple.first (orderRandomArrElement Array.empty seed v) )) - // |> Dict.fromList - - // initGameState = - // GameState gameStateScenario - // players - // 0 - // [] - // [] - // [] - // availableMonsters - // roomCode - - // initOverlays = - // mapTileDataToOverlayList scenario.mapTilesData - - // {- Build a square array capable of holding the whole map - // We add 2 to account for the zero index, and also row drift if the original started on a non-even row - // -} - // arrSize = - // max (abs (bounds.maxX - bounds.minX)) (abs (bounds.maxY - bounds.minY)) - // + 1 - // + (if Bitwise.and bounds.minY 1 == 1 then - // 1 - - // else - // 0 - // ) - - // -- The Y offset needs adjusting if the start of the original array was an odd row - // offsetY = - // if Bitwise.and bounds.minY 1 == 1 then - // bounds.minY - 1 - - // else - // bounds.minY - - // initMap = - // initialize arrSize (always (initialize arrSize (always (Cell [] False)))) - - // initGame = - // setCellsFromMapTiles mapTiles initOverlays bounds.minX offsetY seed (Game initGameState scenario seed [] initMap) - // |> ensureUniqueOverlays - - // startRooms = - // filterMap - // (\o -> - // case o.ref of - // StartingLocation -> - // Just o.cells - - // _ -> - // Nothing - // ) - // initGame.state.overlays - // |> List.foldl (++) [] - // |> filterMap (getRoomsByCoord initGame.staticBoard) - // |> List.foldl (++) [] - // |> uniqueBy (\ref -> Maybe.withDefault "" (refToString ref)) - // in - // revealRooms initGame startRooms - - - // setCellsFromMapTiles : List MapTile -> Dict String ( List BoardOverlay, List ScenarioMonster ) -> Int -> Int -> Seed -> Game -> Game - // setCellsFromMapTiles mapTileList overlays offsetX offsetY seed game = - // case mapTileList of - // head :: rest -> - // let - // ( newGame, newSeed ) = - // setCellFromMapTile game overlays offsetX offsetY head seed - // in - // setCellsFromMapTiles rest overlays offsetX offsetY newSeed newGame - - // _ -> - // game - - - // setCellFromMapTile : Game -> Dict String ( List BoardOverlay, List ScenarioMonster ) -> Int -> Int -> MapTile -> Seed -> ( Game, Seed ) - // setCellFromMapTile game overlays offsetX offsetY tile seed = - // let - // x = - // tile.x - offsetX - - // y = - // tile.y - offsetY - - // refString = - // Maybe.withDefault "" (refToString tile.ref) - - // ( isOrigin, newOrigins ) = - // if tile.originalX == 0 && tile.originalY == 0 then - // ( True, RoomData tile.ref ( x, y ) tile.turns :: game.roomData ) - - // else - // ( False, game.roomData ) - - // state = - // game.state - - // ( boardOverlays, piece ) = - // case Dict.get refString overlays of - // Just ( o, m ) -> - // ( filter (filterByCoord tile.originalX tile.originalY) o - // |> map (mapOverlayCoord tile.originalX tile.originalY x y tile.turns) - // , filter (filterMonsterLevel (List.length game.state.players)) m - // |> filter (\f -> f.initialX == tile.originalX && f.initialY == tile.originalY) - // |> head - // |> getPieceFromMonster (List.length game.state.players) - // |> mapPieceCoord tile.originalX tile.originalY x y - // ) - - // Nothing -> - // ( [], Piece None 0 0 ) - - // doorRefs = - // boardOverlays - // |> filterMap - // (\o -> - // case o.ref of - // Door _ refs -> - // Just refs - - // _ -> - // Nothing - // ) - // |> foldl (++) [] - - // ( monsterBucket, newSeed ) = - // case piece.ref of - // AI (Enemy m) -> - // initialize (getMonsterBucketSize m.monster) identity - // |> orderRandomArrElement Array.empty seed - // |> (\( a, s ) -> ( Just ( Maybe.withDefault "" (monsterTypeToString m.monster), a ), s )) - - // _ -> - // ( Nothing, seed ) - - // newGameState = - // { state - // | overlays = game.state.overlays ++ boardOverlays - // , pieces = - // game.state.pieces - // ++ (case piece.ref of - // None -> - // [] - - // _ -> - // [ piece ] - // ) - // , availableMonsters = - // case monsterBucket of - // Just b -> - // b - // :: Dict.toList game.state.availableMonsters - // |> filter (\( k, _ ) -> k /= "") - // |> Dict.fromList - - // _ -> - // game.state.availableMonsters - // } - - // rowArr = - // Array.get y game.staticBoard - - // newBoard = - // case rowArr of - // Just yRow -> - // let - // cell = - // Array.get x yRow - // in - // case cell of - // Just foundCell -> - // let - // newCell = - // { foundCell - // | passable = - // if foundCell.passable == False then - // tile.passable - - // else - // True - // , rooms = - // tile.ref - // :: (doorRefs ++ foundCell.rooms) - // |> uniqueBy (\r -> Maybe.withDefault "" (refToString r)) - // } - // in - // set y (set x newCell yRow) game.staticBoard - - // Nothing -> - // game.staticBoard - - // Nothing -> - // game.staticBoard - // in - // if tile.passable || (List.length doorRefs > 0) || isOrigin then - // ( { game | state = newGameState, staticBoard = newBoard, roomData = newOrigins } - // , newSeed - // ) - - // else - // ( { game | seed = newSeed }, newSeed ) - - - // filterMonsterLevel : Int -> ScenarioMonster -> Bool - // filterMonsterLevel numPlayers monster = - // if numPlayers < 3 then - // monster.twoPlayer /= Monster.None - - // else if numPlayers < 4 then - // monster.threePlayer /= Monster.None - - // else - // monster.fourPlayer /= Monster.None - - - // getLevelForMonster : Int -> ScenarioMonster -> MonsterLevel - // getLevelForMonster numPlayers monster = - // if numPlayers < 3 then - // monster.twoPlayer - - // else if numPlayers < 4 then - // monster.threePlayer - - // else - // monster.fourPlayer - - - // getPieceFromMonster : Int -> Maybe ScenarioMonster -> Piece - // getPieceFromMonster numPlayers monster = - // case monster of - // Just p -> - // let - // m = - // p.monster - - // level = - // getLevelForMonster numPlayers p - // in - // if level == Monster.None then - // Piece None 0 0 - - // else - // Piece (AI (Enemy { m | level = level })) p.initialX p.initialY - - // Nothing -> - // Piece None 0 0 - - - // getRoomsByCoord : Array (Array Cell) -> ( Int, Int ) -> Maybe (List MapTileRef) - // getRoomsByCoord cells ( x, y ) = - // Array.get y cells - // |> Maybe.andThen - // (\colCell -> - // Array.get x colCell - // |> Maybe.map (\cell -> cell.rooms) - // ) - - - // filterByCoord : Int -> Int -> BoardOverlay -> Bool - // filterByCoord x y overlay = - // case overlay.cells of - // ( overlayX, overlayY ) :: _ -> - // overlayX == x && overlayY == y - - // [] -> - // False - - - // mapPieceCoord : Int -> Int -> Int -> Int -> Piece -> Piece - // mapPieceCoord _ _ newX newY piece = - // { piece | x = newX, y = newY } - - - // mapOverlayCoord : Int -> Int -> Int -> Int -> Int -> BoardOverlay -> BoardOverlay - // mapOverlayCoord originalX originalY newX newY turns overlay = - // let - // ( oX, oY, oZ ) = - // oddRowToCube ( originalX, originalY ) - - // ( nX, nY, nZ ) = - // oddRowToCube ( newX, newY ) - - // diffX = - // nX - oX - - // diffY = - // nY - oY - - // diffZ = - // nZ - oZ - // in - // { overlay - // | cells = - // map - // (\c -> - // let - // ( x1, y1, z1 ) = - // Hexagon.rotate c ( originalX, originalY ) turns - // |> oddRowToCube - // in - // cubeToOddRow ( diffX + x1, diffY + y1, diffZ + z1 ) - // ) - // overlay.cells - // } - - - // movePiece : Piece -> Maybe ( Int, Int ) -> ( Int, Int ) -> Game -> ( Game, Piece ) - // movePiece piece fromCoords ( toX, toY ) game = - // let - // gamestate = - // game.state - - // ( newPieces, newPiece ) = - // movePieceWithoutState piece fromCoords ( toX, toY ) game.state.pieces - - // newGamestate = - // case fromCoords of - // Just ( _, _ ) -> - // { gamestate | pieces = newPieces |> filter (\p -> p /= newPiece) } - - // Nothing -> - // gamestate - // in - // if canMoveTo ( toX, toY ) { game | state = newGamestate } True then - // ( { game | state = { newGamestate | pieces = newPiece :: newGamestate.pieces } } - // , newPiece - // ) - - // else - // ( game, piece ) - - - // movePieceWithoutState : Piece -> Maybe ( Int, Int ) -> ( Int, Int ) -> List Piece -> ( List Piece, Piece ) - // movePieceWithoutState piece fromCoords ( toX, toY ) pieces = - // let - // newPiece = - // { piece | x = toX, y = toY } - - // newPieces = - // case fromCoords of - // Just ( fromX, fromY ) -> - // filter (removePiece { piece | x = fromX, y = fromY }) pieces - - // Nothing -> - // pieces - // in - // if List.any (\p -> p.x == toX && p.y == toY) newPieces then - // ( pieces, piece ) - - // else - // ( newPiece :: newPieces, newPiece ) - - - // moveOverlay : BoardOverlay -> Maybe ( Int, Int ) -> Maybe ( Int, Int ) -> ( Int, Int ) -> Game -> ( Game, BoardOverlay, Maybe ( Int, Int ) ) - // moveOverlay overlay fromCoords prevCoords ( toX, toY ) game = - // let - // gamestate = - // game.state - - // ( newOverlays, newOverlay, _ ) = - // moveOverlayWithoutState overlay fromCoords prevCoords ( toX, toY ) game.state.overlays - - // newGamestate = - // case fromCoords of - // Just _ -> - // { gamestate - // | overlays = - // newOverlays - // |> filter (\o -> o /= newOverlay) - // } - - // Nothing -> - // gamestate - - // newGame = - // { game | state = newGamestate } - // in - // if all (\c -> canMoveTo c newGame True) newOverlay.cells then - // ( { game | state = { newGamestate | overlays = newOverlay :: newGamestate.overlays } } - // , newOverlay - // , Just ( toX, toY ) - // ) - - // else - // ( game, overlay, prevCoords ) - - - // moveOverlayWithoutState : BoardOverlay -> Maybe ( Int, Int ) -> Maybe ( Int, Int ) -> ( Int, Int ) -> List BoardOverlay -> ( List BoardOverlay, BoardOverlay, Maybe ( Int, Int ) ) - // moveOverlayWithoutState overlay fromCoords prevCoords ( toX, toY ) overlays = - // let - // ( fromX, fromY, fromZ ) = - // case fromCoords of - // Just ( oX, oY ) -> - // oddRowToCube ( oX, oY ) - - // Nothing -> - // ( 0, 0, 0 ) - - // ( prevDiffX, prevDiffY, prevDiffZ ) = - // case prevCoords of - // Just p -> - // let - // ( pX, pY, pZ ) = - // oddRowToCube p - // in - // ( fromX - pX, fromY - pY, fromZ - pZ ) - - // Nothing -> - // ( 0, 0, 0 ) - - // ( diffX, diffY, diffZ ) = - // let - // ( dX, dY, dZ ) = - // case fromCoords of - // Just _ -> - // let - // ( newX, newY, newZ ) = - // oddRowToCube ( toX, toY ) - // in - // ( newX - fromX, newY - fromY, newZ - fromZ ) - - // Nothing -> - // oddRowToCube ( toX, toY ) - // in - // ( dX + prevDiffX, dY + prevDiffY, dZ + prevDiffZ ) - - // moveCells c = - // let - // ( cX, cY, cZ ) = - // oddRowToCube c - // in - // cubeToOddRow ( cX + diffX, cY + diffY, cZ + diffZ ) - - // newOverlay = - // { overlay | cells = map moveCells overlay.cells } - - // newOverlays = - // case fromCoords of - // Just _ -> - // filter - // (\o -> o.id /= overlay.id) - // overlays - - // Nothing -> - // overlays - // in - // ( newOverlays - // , newOverlay - // , Just ( toX, toY ) - // ) - - - // revealRooms : Game -> List MapTileRef -> Game - // revealRooms game rooms = - // case rooms of - // room :: rest -> - // revealRooms (revealRoom room game) rest - - // _ -> - // game - - - // revealRoom : MapTileRef -> Game -> Game - // revealRoom room game = - // if member room game.state.visibleRooms then - // game - - // else - // let - // roomCells = - // indexedMap (\y arr -> indexedMap (\x cell -> ( cell, ( x, y ) )) arr) game.staticBoard - // |> Array.foldl (\a b -> fromList (toList a ++ toList b)) Array.empty - // |> toList - // |> filter (\( cell, _ ) -> cell.passable && member room cell.rooms) - // |> map (\( _, c ) -> c) - - // ( assignedMonsters, availableMonsters ) = - // filterMap - // (\p -> - // case p.ref of - // AI (Enemy e) -> - // if member ( p.x, p.y ) roomCells && e.id == 0 then - // Just p - - // else - // Nothing - - // _ -> - // Nothing - // ) - // game.state.pieces - // |> assignIdentifiers game.state.availableMonsters [] - // |> (\( m, a ) -> - // ( filterMap - // (\p -> - // case p.ref of - // AI (Enemy e) -> - // if e.id /= 0 then - // Just p - - // else - // Nothing - - // _ -> - // Nothing - // ) - // m - // , a - // ) - // ) - - // ignoredPieces = - // filterMap - // (\p -> - // case p.ref of - // AI (Enemy e) -> - // if member ( p.x, p.y ) roomCells && e.id == 0 then - // Nothing - - // else - // Just p - - // _ -> - // Just p - // ) - // game.state.pieces - - // state = - // game.state - - // newGame = - // { game | state = { state | visibleRooms = room :: state.visibleRooms, availableMonsters = availableMonsters, pieces = ignoredPieces ++ assignedMonsters } } - - // corridors = - // game.state.overlays - // |> filter - // (\o -> - // case o.ref of - // Door (Corridor m _) refs -> - // case m of - // Dark -> - // False - - // _ -> - // member room refs - - // _ -> - // False - // ) - // |> filterMap - // (\o -> - // case o.ref of - // Door (Corridor _ _) refs -> - // Just refs - - // _ -> - // Nothing - // ) - // |> foldl (++) [] - // |> filter (\r -> r /= room) - // in - // revealRooms newGame corridors - - - // removePieceFromBoard : Piece -> Game -> Game - // removePieceFromBoard piece game = - // let - // gameState = - // game.state - - // filteredPieces = - // filter (removePiece piece) gameState.pieces - - // newAvailableMonsters = - // case piece.ref of - // AI (Enemy m) -> - // let - // ref = - // Maybe.withDefault "" (monsterTypeToString m.monster) - // in - // case Dict.get ref gameState.availableMonsters of - // Just v -> - // insert ref (push (m.id - 1) v) gameState.availableMonsters - - // Nothing -> - // insert ref (fromList [ m.id - 1 ]) gameState.availableMonsters - - // _ -> - // gameState.availableMonsters - - // newOverlays = - // case piece.ref of - // AI (Enemy m) -> - // if m.wasSummoned then - // gameState.overlays - - // else if - // any - // (\o -> - // case o.ref of - // Treasure (Coin _) -> - // member ( piece.x, piece.y ) o.cells - - // _ -> - // False - // ) - // gameState.overlays - // then - // map - // (\o -> - // case o.ref of - // Treasure (Coin i) -> - // if member ( piece.x, piece.y ) o.cells then - // { o | ref = Treasure (Coin (i + 1)) } - - // else - // o - - // _ -> - // o - // ) - // gameState.overlays - - // else - // let - // maxId = - // case - // List.map (\o -> o.id) gameState.overlays - // |> List.maximum - // of - // Just i -> - // i - - // Nothing -> - // 0 - // in - // BoardOverlay (Treasure (Coin 1)) (maxId + 1) Default [ ( piece.x, piece.y ) ] - // :: gameState.overlays - - // _ -> - // gameState.overlays - // in - // { game | state = { gameState | pieces = filteredPieces, overlays = newOverlays, availableMonsters = newAvailableMonsters } } - - - // assignIdentifiers : Dict String (Array Int) -> List Piece -> List Piece -> ( List Piece, Dict String (Array Int) ) - // assignIdentifiers availableMonsters processed monsters = - // case monsters of - // m :: rest -> - // let - // ( newM, newBucket ) = - // assignIdentifier availableMonsters m - // in - // assignIdentifiers newBucket (newM :: processed) rest - - // _ -> - // ( processed, availableMonsters ) - - - // assignIdentifier : Dict String (Array Int) -> Piece -> ( Piece, Dict String (Array Int) ) - // assignIdentifier availableMonsters p = - // case p.ref of - // AI (Enemy monster) -> - // case monsterTypeToString monster.monster of - // Just key -> - // case Dict.get key availableMonsters of - // Just bucket -> - // case Array.get 0 bucket of - // Just id -> - // ( { p | ref = AI (Enemy { monster | id = id + 1 }) }, insert key (slice 1 (length bucket) bucket) availableMonsters ) - - // Nothing -> - // ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) - - // Nothing -> - // ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) - - // Nothing -> - // ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) - - // _ -> - // ( p, availableMonsters ) - - - // removePiece : Piece -> Piece -> Bool - // removePiece pieceToRemove comparePiece = - // pieceToRemove.ref - // /= comparePiece.ref - - - // canMoveTo : ( Int, Int ) -> Game -> Bool -> Bool - // canMoveTo ( toX, toY ) game ignoreObstacles = - // let - // obstacleList = - // if ignoreObstacles then - // [] - - // else - // game.state.overlays - // |> filter - // (\o -> - // case o.ref of - // Obstacle _ -> - // True - - // Trap _ -> - // True - - // Door (Corridor _ _) _ -> - // False - - // Door _ _ -> - // True - - // _ -> - // False - // ) - // in - // case Array.get toY game.staticBoard of - // Just row -> - // case Array.get toX row of - // Just cell -> - // any (\c -> List.member c cell.rooms) game.state.visibleRooms - // && cell.passable - // && all (\p -> p.x /= toX || p.y /= toY) game.state.pieces - // && (ignoreObstacles - // || all (\o -> List.all (\c -> c /= ( toX, toY )) o.cells) obstacleList - // ) - - // Nothing -> - // False - - // Nothing -> - // False - - - // orderRandomArrElement : Array a -> Seed -> Array a -> ( Array a, Seed ) - // orderRandomArrElement bucket seed original = - // if length original == 0 then - // ( bucket, seed ) - - // else - // let - // ( index, newSeed ) = - // Random.step (Random.int 0 (length original - 1)) seed - - // slice1 = - // toList (slice 0 index original) - - // slice2 = - // toList (slice (index + 1) (length original) original) - // in - // case Array.get index original of - // Just o -> - // orderRandomArrElement (push o bucket) newSeed (fromList (slice1 ++ slice2)) - - // Nothing -> - // ( bucket, seed ) - - - // assignPlayers : List CharacterClass -> Game -> Game - // assignPlayers players game = - // let - // state = - // game.state - - // filteredPieces = - // filter - // (\p -> - // case p.ref of - // AI (Enemy _) -> - // True - - // _ -> - // False - // ) - // state.pieces - - // statingLocations = - // filter - // (\o -> - // case o.ref of - // StartingLocation -> - // True - - // _ -> - // False - // ) - // state.overlays - // in - // { game | state = { state | players = players, pieces = assignPlayersToPiece players filteredPieces statingLocations } } - - - // assignPlayersToPiece : List CharacterClass -> List Piece -> List BoardOverlay -> List Piece - // assignPlayersToPiece players pieces startingLocations = - // let - // filteredLocations = - // filter - // (\o -> - // case o.ref of - // StartingLocation -> - // True - - // _ -> - // False - // ) - // startingLocations - // in - // case players of - // player :: rest -> - // case filteredLocations of - // location :: otherLocations -> - // case head location.cells of - // Just ( x, y ) -> - // assignPlayersToPiece rest (Piece (Player player) x y :: pieces) otherLocations - - // Nothing -> - // pieces - - // _ -> - // pieces - - // _ -> - // pieces - - - // ensureUniqueOverlays : Game -> Game - // ensureUniqueOverlays game = - // let - // state = - // game.state - - // overlays = - // state.overlays - // |> uniqueBy - // (\o -> - // cellsToString o.cells ++ Maybe.withDefault "" (getBoardOverlayName o.ref) - // ) - - // pieces = - // state.pieces - // |> uniqueBy - // (\p -> - // String.fromInt p.x ++ "x" ++ String.fromInt p.y - // ) - // in - // { game | state = { state | overlays = overlays, pieces = pieces } } - - - // cellsToString : List ( Int, Int ) -> String - // cellsToString cells = - // cells - // |> map (\( x, y ) -> String.fromInt x ++ "x" ++ String.fromInt y) - // |> foldl (\s b -> s ++ "|" ++ b) "" + GameState(GameStateScenario.InbuiltScenario(Expansion.Gloomhaven, 1), Nil, 0, Nil, Nil, Nil, Map.empty, "") + +// def getPieceType(piece: PieceType): String = +// piece match +// case Player(_) => +// "player" + +// case AI(t) => +// t match +// case Summons(_) => +// "player" + +// case Enemy(_) => +// "monster" + +// case None => +// "" + +// def getPieceName(piece: PieceType): String = +// piece match +// case Player(p) => +// Character.characterToString(p).getOrElse("") + +// case AI(t) => +// t match +// case Summons(_) => +// "summons" + +// case Enemy(e)=> +// Monster.monsterTypeToString(e.monster).getOrElse("") + +// case None => +// "" + +// generateGameMap : GameStateScenario -> Scenario -> String -> List CharacterClass -> Seed -> Game +// generateGameMap gameStateScenario scenario roomCode players seed = +// let +// ( mapTiles, bounds ) = +// mapTileDataToList scenario.mapTilesData Nothing + +// availableMonsters = +// map (\m -> ( Maybe.withDefault "" (monsterTypeToString m), initialize (getMonsterBucketSize m) identity )) scenario.additionalMonsters +// |> filter (\( k, _ ) -> k /= "") +// |> map (\( k, v ) -> ( k, Tuple.first (orderRandomArrElement Array.empty seed v) )) +// |> Dict.fromList + +// initGameState = +// GameState gameStateScenario +// players +// 0 +// [] +// [] +// [] +// availableMonsters +// roomCode + +// initOverlays = +// mapTileDataToOverlayList scenario.mapTilesData + +// {- Build a square array capable of holding the whole map +// We add 2 to account for the zero index, and also row drift if the original started on a non-even row +// -} +// arrSize = +// max (abs (bounds.maxX - bounds.minX)) (abs (bounds.maxY - bounds.minY)) +// + 1 +// + (if Bitwise.and bounds.minY 1 == 1 then +// 1 + +// else +// 0 +// ) + +// -- The Y offset needs adjusting if the start of the original array was an odd row +// offsetY = +// if Bitwise.and bounds.minY 1 == 1 then +// bounds.minY - 1 + +// else +// bounds.minY + +// initMap = +// initialize arrSize (always (initialize arrSize (always (Cell [] False)))) + +// initGame = +// setCellsFromMapTiles mapTiles initOverlays bounds.minX offsetY seed (Game initGameState scenario seed [] initMap) +// |> ensureUniqueOverlays + +// startRooms = +// filterMap +// (\o -> +// case o.ref of +// StartingLocation -> +// Just o.cells + +// _ -> +// Nothing +// ) +// initGame.state.overlays +// |> List.foldl (++) [] +// |> filterMap (getRoomsByCoord initGame.staticBoard) +// |> List.foldl (++) [] +// |> uniqueBy (\ref -> Maybe.withDefault "" (refToString ref)) +// in +// revealRooms initGame startRooms + +// setCellsFromMapTiles : List MapTile -> Dict String ( List BoardOverlay, List ScenarioMonster ) -> Int -> Int -> Seed -> Game -> Game +// setCellsFromMapTiles mapTileList overlays offsetX offsetY seed game = +// case mapTileList of +// head :: rest -> +// let +// ( newGame, newSeed ) = +// setCellFromMapTile game overlays offsetX offsetY head seed +// in +// setCellsFromMapTiles rest overlays offsetX offsetY newSeed newGame + +// _ -> +// game + +// setCellFromMapTile : Game -> Dict String ( List BoardOverlay, List ScenarioMonster ) -> Int -> Int -> MapTile -> Seed -> ( Game, Seed ) +// setCellFromMapTile game overlays offsetX offsetY tile seed = +// let +// x = +// tile.x - offsetX + +// y = +// tile.y - offsetY + +// refString = +// Maybe.withDefault "" (refToString tile.ref) + +// ( isOrigin, newOrigins ) = +// if tile.originalX == 0 && tile.originalY == 0 then +// ( True, RoomData tile.ref ( x, y ) tile.turns :: game.roomData ) + +// else +// ( False, game.roomData ) + +// state = +// game.state + +// ( boardOverlays, piece ) = +// case Dict.get refString overlays of +// Just ( o, m ) -> +// ( filter (filterByCoord tile.originalX tile.originalY) o +// |> map (mapOverlayCoord tile.originalX tile.originalY x y tile.turns) +// , filter (filterMonsterLevel (List.length game.state.players)) m +// |> filter (\f -> f.initialX == tile.originalX && f.initialY == tile.originalY) +// |> head +// |> getPieceFromMonster (List.length game.state.players) +// |> mapPieceCoord tile.originalX tile.originalY x y +// ) + +// Nothing -> +// ( [], Piece None 0 0 ) + +// doorRefs = +// boardOverlays +// |> filterMap +// (\o -> +// case o.ref of +// Door _ refs -> +// Just refs + +// _ -> +// Nothing +// ) +// |> foldl (++) [] + +// ( monsterBucket, newSeed ) = +// case piece.ref of +// AI (Enemy m) -> +// initialize (getMonsterBucketSize m.monster) identity +// |> orderRandomArrElement Array.empty seed +// |> (\( a, s ) -> ( Just ( Maybe.withDefault "" (monsterTypeToString m.monster), a ), s )) + +// _ -> +// ( Nothing, seed ) + +// newGameState = +// { state +// | overlays = game.state.overlays ++ boardOverlays +// , pieces = +// game.state.pieces +// ++ (case piece.ref of +// None -> +// [] + +// _ -> +// [ piece ] +// ) +// , availableMonsters = +// case monsterBucket of +// Just b -> +// b +// :: Dict.toList game.state.availableMonsters +// |> filter (\( k, _ ) -> k /= "") +// |> Dict.fromList + +// _ -> +// game.state.availableMonsters +// } + +// rowArr = +// Array.get y game.staticBoard + +// newBoard = +// case rowArr of +// Just yRow -> +// let +// cell = +// Array.get x yRow +// in +// case cell of +// Just foundCell -> +// let +// newCell = +// { foundCell +// | passable = +// if foundCell.passable == False then +// tile.passable + +// else +// True +// , rooms = +// tile.ref +// :: (doorRefs ++ foundCell.rooms) +// |> uniqueBy (\r -> Maybe.withDefault "" (refToString r)) +// } +// in +// set y (set x newCell yRow) game.staticBoard + +// Nothing -> +// game.staticBoard + +// Nothing -> +// game.staticBoard +// in +// if tile.passable || (List.length doorRefs > 0) || isOrigin then +// ( { game | state = newGameState, staticBoard = newBoard, roomData = newOrigins } +// , newSeed +// ) + +// else +// ( { game | seed = newSeed }, newSeed ) + +// filterMonsterLevel : Int -> ScenarioMonster -> Bool +// filterMonsterLevel numPlayers monster = +// if numPlayers < 3 then +// monster.twoPlayer /= Monster.None + +// else if numPlayers < 4 then +// monster.threePlayer /= Monster.None + +// else +// monster.fourPlayer /= Monster.None + +// getLevelForMonster : Int -> ScenarioMonster -> MonsterLevel +// getLevelForMonster numPlayers monster = +// if numPlayers < 3 then +// monster.twoPlayer + +// else if numPlayers < 4 then +// monster.threePlayer + +// else +// monster.fourPlayer + +// getPieceFromMonster : Int -> Maybe ScenarioMonster -> Piece +// getPieceFromMonster numPlayers monster = +// case monster of +// Just p -> +// let +// m = +// p.monster + +// level = +// getLevelForMonster numPlayers p +// in +// if level == Monster.None then +// Piece None 0 0 + +// else +// Piece (AI (Enemy { m | level = level })) p.initialX p.initialY + +// Nothing -> +// Piece None 0 0 + +// getRoomsByCoord : Array (Array Cell) -> ( Int, Int ) -> Maybe (List MapTileRef) +// getRoomsByCoord cells ( x, y ) = +// Array.get y cells +// |> Maybe.andThen +// (\colCell -> +// Array.get x colCell +// |> Maybe.map (\cell -> cell.rooms) +// ) + +// filterByCoord : Int -> Int -> BoardOverlay -> Bool +// filterByCoord x y overlay = +// case overlay.cells of +// ( overlayX, overlayY ) :: _ -> +// overlayX == x && overlayY == y + +// [] -> +// False + +// mapPieceCoord : Int -> Int -> Int -> Int -> Piece -> Piece +// mapPieceCoord _ _ newX newY piece = +// { piece | x = newX, y = newY } + +// mapOverlayCoord : Int -> Int -> Int -> Int -> Int -> BoardOverlay -> BoardOverlay +// mapOverlayCoord originalX originalY newX newY turns overlay = +// let +// ( oX, oY, oZ ) = +// oddRowToCube ( originalX, originalY ) + +// ( nX, nY, nZ ) = +// oddRowToCube ( newX, newY ) + +// diffX = +// nX - oX + +// diffY = +// nY - oY + +// diffZ = +// nZ - oZ +// in +// { overlay +// | cells = +// map +// (\c -> +// let +// ( x1, y1, z1 ) = +// Hexagon.rotate c ( originalX, originalY ) turns +// |> oddRowToCube +// in +// cubeToOddRow ( diffX + x1, diffY + y1, diffZ + z1 ) +// ) +// overlay.cells +// } + +// movePiece : Piece -> Maybe ( Int, Int ) -> ( Int, Int ) -> Game -> ( Game, Piece ) +// movePiece piece fromCoords ( toX, toY ) game = +// let +// gamestate = +// game.state + +// ( newPieces, newPiece ) = +// movePieceWithoutState piece fromCoords ( toX, toY ) game.state.pieces + +// newGamestate = +// case fromCoords of +// Just ( _, _ ) -> +// { gamestate | pieces = newPieces |> filter (\p -> p /= newPiece) } + +// Nothing -> +// gamestate +// in +// if canMoveTo ( toX, toY ) { game | state = newGamestate } True then +// ( { game | state = { newGamestate | pieces = newPiece :: newGamestate.pieces } } +// , newPiece +// ) + +// else +// ( game, piece ) + +// movePieceWithoutState : Piece -> Maybe ( Int, Int ) -> ( Int, Int ) -> List Piece -> ( List Piece, Piece ) +// movePieceWithoutState piece fromCoords ( toX, toY ) pieces = +// let +// newPiece = +// { piece | x = toX, y = toY } + +// newPieces = +// case fromCoords of +// Just ( fromX, fromY ) -> +// filter (removePiece { piece | x = fromX, y = fromY }) pieces + +// Nothing -> +// pieces +// in +// if List.any (\p -> p.x == toX && p.y == toY) newPieces then +// ( pieces, piece ) + +// else +// ( newPiece :: newPieces, newPiece ) + +// moveOverlay : BoardOverlay -> Maybe ( Int, Int ) -> Maybe ( Int, Int ) -> ( Int, Int ) -> Game -> ( Game, BoardOverlay, Maybe ( Int, Int ) ) +// moveOverlay overlay fromCoords prevCoords ( toX, toY ) game = +// let +// gamestate = +// game.state + +// ( newOverlays, newOverlay, _ ) = +// moveOverlayWithoutState overlay fromCoords prevCoords ( toX, toY ) game.state.overlays + +// newGamestate = +// case fromCoords of +// Just _ -> +// { gamestate +// | overlays = +// newOverlays +// |> filter (\o -> o /= newOverlay) +// } + +// Nothing -> +// gamestate + +// newGame = +// { game | state = newGamestate } +// in +// if all (\c -> canMoveTo c newGame True) newOverlay.cells then +// ( { game | state = { newGamestate | overlays = newOverlay :: newGamestate.overlays } } +// , newOverlay +// , Just ( toX, toY ) +// ) + +// else +// ( game, overlay, prevCoords ) + +// moveOverlayWithoutState : BoardOverlay -> Maybe ( Int, Int ) -> Maybe ( Int, Int ) -> ( Int, Int ) -> List BoardOverlay -> ( List BoardOverlay, BoardOverlay, Maybe ( Int, Int ) ) +// moveOverlayWithoutState overlay fromCoords prevCoords ( toX, toY ) overlays = +// let +// ( fromX, fromY, fromZ ) = +// case fromCoords of +// Just ( oX, oY ) -> +// oddRowToCube ( oX, oY ) + +// Nothing -> +// ( 0, 0, 0 ) + +// ( prevDiffX, prevDiffY, prevDiffZ ) = +// case prevCoords of +// Just p -> +// let +// ( pX, pY, pZ ) = +// oddRowToCube p +// in +// ( fromX - pX, fromY - pY, fromZ - pZ ) + +// Nothing -> +// ( 0, 0, 0 ) + +// ( diffX, diffY, diffZ ) = +// let +// ( dX, dY, dZ ) = +// case fromCoords of +// Just _ -> +// let +// ( newX, newY, newZ ) = +// oddRowToCube ( toX, toY ) +// in +// ( newX - fromX, newY - fromY, newZ - fromZ ) + +// Nothing -> +// oddRowToCube ( toX, toY ) +// in +// ( dX + prevDiffX, dY + prevDiffY, dZ + prevDiffZ ) + +// moveCells c = +// let +// ( cX, cY, cZ ) = +// oddRowToCube c +// in +// cubeToOddRow ( cX + diffX, cY + diffY, cZ + diffZ ) + +// newOverlay = +// { overlay | cells = map moveCells overlay.cells } + +// newOverlays = +// case fromCoords of +// Just _ -> +// filter +// (\o -> o.id /= overlay.id) +// overlays + +// Nothing -> +// overlays +// in +// ( newOverlays +// , newOverlay +// , Just ( toX, toY ) +// ) + +// revealRooms : Game -> List MapTileRef -> Game +// revealRooms game rooms = +// case rooms of +// room :: rest -> +// revealRooms (revealRoom room game) rest + +// _ -> +// game + +// revealRoom : MapTileRef -> Game -> Game +// revealRoom room game = +// if member room game.state.visibleRooms then +// game + +// else +// let +// roomCells = +// indexedMap (\y arr -> indexedMap (\x cell -> ( cell, ( x, y ) )) arr) game.staticBoard +// |> Array.foldl (\a b -> fromList (toList a ++ toList b)) Array.empty +// |> toList +// |> filter (\( cell, _ ) -> cell.passable && member room cell.rooms) +// |> map (\( _, c ) -> c) + +// ( assignedMonsters, availableMonsters ) = +// filterMap +// (\p -> +// case p.ref of +// AI (Enemy e) -> +// if member ( p.x, p.y ) roomCells && e.id == 0 then +// Just p + +// else +// Nothing + +// _ -> +// Nothing +// ) +// game.state.pieces +// |> assignIdentifiers game.state.availableMonsters [] +// |> (\( m, a ) -> +// ( filterMap +// (\p -> +// case p.ref of +// AI (Enemy e) -> +// if e.id /= 0 then +// Just p + +// else +// Nothing + +// _ -> +// Nothing +// ) +// m +// , a +// ) +// ) + +// ignoredPieces = +// filterMap +// (\p -> +// case p.ref of +// AI (Enemy e) -> +// if member ( p.x, p.y ) roomCells && e.id == 0 then +// Nothing + +// else +// Just p + +// _ -> +// Just p +// ) +// game.state.pieces + +// state = +// game.state + +// newGame = +// { game | state = { state | visibleRooms = room :: state.visibleRooms, availableMonsters = availableMonsters, pieces = ignoredPieces ++ assignedMonsters } } + +// corridors = +// game.state.overlays +// |> filter +// (\o -> +// case o.ref of +// Door (Corridor m _) refs -> +// case m of +// Dark -> +// False + +// _ -> +// member room refs + +// _ -> +// False +// ) +// |> filterMap +// (\o -> +// case o.ref of +// Door (Corridor _ _) refs -> +// Just refs + +// _ -> +// Nothing +// ) +// |> foldl (++) [] +// |> filter (\r -> r /= room) +// in +// revealRooms newGame corridors + +// removePieceFromBoard : Piece -> Game -> Game +// removePieceFromBoard piece game = +// let +// gameState = +// game.state + +// filteredPieces = +// filter (removePiece piece) gameState.pieces + +// newAvailableMonsters = +// case piece.ref of +// AI (Enemy m) -> +// let +// ref = +// Maybe.withDefault "" (monsterTypeToString m.monster) +// in +// case Dict.get ref gameState.availableMonsters of +// Just v -> +// insert ref (push (m.id - 1) v) gameState.availableMonsters + +// Nothing -> +// insert ref (fromList [ m.id - 1 ]) gameState.availableMonsters + +// _ -> +// gameState.availableMonsters + +// newOverlays = +// case piece.ref of +// AI (Enemy m) -> +// if m.wasSummoned then +// gameState.overlays + +// else if +// any +// (\o -> +// case o.ref of +// Treasure (Coin _) -> +// member ( piece.x, piece.y ) o.cells + +// _ -> +// False +// ) +// gameState.overlays +// then +// map +// (\o -> +// case o.ref of +// Treasure (Coin i) -> +// if member ( piece.x, piece.y ) o.cells then +// { o | ref = Treasure (Coin (i + 1)) } + +// else +// o + +// _ -> +// o +// ) +// gameState.overlays + +// else +// let +// maxId = +// case +// List.map (\o -> o.id) gameState.overlays +// |> List.maximum +// of +// Just i -> +// i + +// Nothing -> +// 0 +// in +// BoardOverlay (Treasure (Coin 1)) (maxId + 1) Default [ ( piece.x, piece.y ) ] +// :: gameState.overlays + +// _ -> +// gameState.overlays +// in +// { game | state = { gameState | pieces = filteredPieces, overlays = newOverlays, availableMonsters = newAvailableMonsters } } + +// assignIdentifiers : Dict String (Array Int) -> List Piece -> List Piece -> ( List Piece, Dict String (Array Int) ) +// assignIdentifiers availableMonsters processed monsters = +// case monsters of +// m :: rest -> +// let +// ( newM, newBucket ) = +// assignIdentifier availableMonsters m +// in +// assignIdentifiers newBucket (newM :: processed) rest + +// _ -> +// ( processed, availableMonsters ) + +// assignIdentifier : Dict String (Array Int) -> Piece -> ( Piece, Dict String (Array Int) ) +// assignIdentifier availableMonsters p = +// case p.ref of +// AI (Enemy monster) -> +// case monsterTypeToString monster.monster of +// Just key -> +// case Dict.get key availableMonsters of +// Just bucket -> +// case Array.get 0 bucket of +// Just id -> +// ( { p | ref = AI (Enemy { monster | id = id + 1 }) }, insert key (slice 1 (length bucket) bucket) availableMonsters ) + +// Nothing -> +// ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) + +// Nothing -> +// ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) + +// Nothing -> +// ( { p | ref = AI (Enemy { monster | id = 0 }) }, availableMonsters ) + +// _ -> +// ( p, availableMonsters ) + +// removePiece : Piece -> Piece -> Bool +// removePiece pieceToRemove comparePiece = +// pieceToRemove.ref +// /= comparePiece.ref + +// canMoveTo : ( Int, Int ) -> Game -> Bool -> Bool +// canMoveTo ( toX, toY ) game ignoreObstacles = +// let +// obstacleList = +// if ignoreObstacles then +// [] + +// else +// game.state.overlays +// |> filter +// (\o -> +// case o.ref of +// Obstacle _ -> +// True + +// Trap _ -> +// True + +// Door (Corridor _ _) _ -> +// False + +// Door _ _ -> +// True + +// _ -> +// False +// ) +// in +// case Array.get toY game.staticBoard of +// Just row -> +// case Array.get toX row of +// Just cell -> +// any (\c -> List.member c cell.rooms) game.state.visibleRooms +// && cell.passable +// && all (\p -> p.x /= toX || p.y /= toY) game.state.pieces +// && (ignoreObstacles +// || all (\o -> List.all (\c -> c /= ( toX, toY )) o.cells) obstacleList +// ) + +// Nothing -> +// False + +// Nothing -> +// False + +// orderRandomArrElement : Array a -> Seed -> Array a -> ( Array a, Seed ) +// orderRandomArrElement bucket seed original = +// if length original == 0 then +// ( bucket, seed ) + +// else +// let +// ( index, newSeed ) = +// Random.step (Random.int 0 (length original - 1)) seed + +// slice1 = +// toList (slice 0 index original) + +// slice2 = +// toList (slice (index + 1) (length original) original) +// in +// case Array.get index original of +// Just o -> +// orderRandomArrElement (push o bucket) newSeed (fromList (slice1 ++ slice2)) + +// Nothing -> +// ( bucket, seed ) + +// assignPlayers : List CharacterClass -> Game -> Game +// assignPlayers players game = +// let +// state = +// game.state + +// filteredPieces = +// filter +// (\p -> +// case p.ref of +// AI (Enemy _) -> +// True + +// _ -> +// False +// ) +// state.pieces + +// statingLocations = +// filter +// (\o -> +// case o.ref of +// StartingLocation -> +// True + +// _ -> +// False +// ) +// state.overlays +// in +// { game | state = { state | players = players, pieces = assignPlayersToPiece players filteredPieces statingLocations } } + +// assignPlayersToPiece : List CharacterClass -> List Piece -> List BoardOverlay -> List Piece +// assignPlayersToPiece players pieces startingLocations = +// let +// filteredLocations = +// filter +// (\o -> +// case o.ref of +// StartingLocation -> +// True + +// _ -> +// False +// ) +// startingLocations +// in +// case players of +// player :: rest -> +// case filteredLocations of +// location :: otherLocations -> +// case head location.cells of +// Just ( x, y ) -> +// assignPlayersToPiece rest (Piece (Player player) x y :: pieces) otherLocations + +// Nothing -> +// pieces + +// _ -> +// pieces + +// _ -> +// pieces + +// ensureUniqueOverlays : Game -> Game +// ensureUniqueOverlays game = +// let +// state = +// game.state + +// overlays = +// state.overlays +// |> uniqueBy +// (\o -> +// cellsToString o.cells ++ Maybe.withDefault "" (getBoardOverlayName o.ref) +// ) + +// pieces = +// state.pieces +// |> uniqueBy +// (\p -> +// String.fromInt p.x ++ "x" ++ String.fromInt p.y +// ) +// in +// { game | state = { state | overlays = overlays, pieces = pieces } } + +// cellsToString : List ( Int, Int ) -> String +// cellsToString cells = +// cells +// |> map (\( x, y ) -> String.fromInt x ++ "x" ++ String.fromInt y) +// |> foldl (\s b -> s ++ "|" ++ b) "" enum AIType: - case Enemy(monster: Monster) - case Summons(summons: SummonsType) + case Enemy(monster: Monster) + case Summons(summons: SummonsType) enum SummonsType: - case NormalSummons(i: Int, color: Colour) // TODO: What is 'i'? - case BearSummons + case NormalSummons(i: Int, color: Colour) // TODO: What is 'i'? + case BearSummons enum PieceType: - case None - case Player(cls: CharacterClass) - case AI(typ: AIType) - -final case class Piece - ( ref : PieceType - , x : Int - , y : Int - ) - -final case class Cell - ( rooms : List[MapTileRef] - , passable : Boolean - ) - -final case class Game - ( state : GameState - , scenario : Scenario - , seed : Long - , roomData : List[RoomData] - , staticBoard : List[List[Cell]] - ) - -final case class GameState - ( scenario : GameStateScenario - , players : List[CharacterClass] - , updateCount : Int - , visibleRooms : List[MapTileRef] - , overlays : List[BoardOverlay] - , pieces : List[Piece] - , availableMonsters : Map[String, List[Int]] - , roomCode : String - ) + case None + case Player(cls: CharacterClass) + case AI(typ: AIType) + +final case class Piece(ref: PieceType, x: Int, y: Int) + +final case class Cell(rooms: List[MapTileRef], passable: Boolean) + +final case class Game( + state: GameState, + scenario: Scenario, + seed: Long, + roomData: List[RoomData], + staticBoard: List[List[Cell]] +) + +final case class GameState( + scenario: GameStateScenario, + players: List[CharacterClass], + updateCount: Int, + visibleRooms: List[MapTileRef], + overlays: List[BoardOverlay], + pieces: List[Piece], + availableMonsters: Map[String, List[Int]], + roomCode: String +) enum GameStateScenario: - case InbuiltScenario(exp: Expansion, i: Int) // TODO: What is 'i'? - case CustomScenario(data: String) + case InbuiltScenario(exp: Expansion, i: Int) // TODO: What is 'i'? + case CustomScenario(data: String) enum Expansion: - case Gloomhaven - case Solo - -final case class RoomData - ( ref : MapTileRef - , origin : ( Int, Int ) - , turns : Int - ) + case Gloomhaven + case Solo + +final case class RoomData(ref: MapTileRef, origin: (Int, Int), turns: Int) From 458a6f94ccb7e16df03b41d6a95abba677b6dc53 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 10 Apr 2023 09:03:57 +0100 Subject: [PATCH 22/60] A few chunks of Main --- ui/ui/src/vgb/Main.scala | 139 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 10 deletions(-) diff --git a/ui/ui/src/vgb/Main.scala b/ui/ui/src/vgb/Main.scala index 30be9858..c3d5705e 100644 --- a/ui/ui/src/vgb/Main.scala +++ b/ui/ui/src/vgb/Main.scala @@ -5,28 +5,147 @@ import tyrian.Html.* import tyrian.* import scala.scalajs.js.annotation.* +import org.scalajs.dom.Element @JSExportTopLevel("TyrianApp") object Main extends TyrianApp[Msg, Model]: def init(flags: Map[String, String]): (Model, Cmd[IO, Msg]) = - (0, Cmd.None) + (???, Cmd.None) def update(model: Model): Msg => (Model, Cmd[IO, Msg]) = - case Msg.Increment => (model + 1, Cmd.None) - case Msg.Decrement => (model - 1, Cmd.None) + _ => (model, Cmd.None) def view(model: Model): Html[Msg] = - div()( - button(onClick(Msg.Decrement))(text("-")), - div()(text(model.toString)), - button(onClick(Msg.Increment))(text("+")) - ) + div()() def subscriptions(model: Model): Sub[IO, Msg] = Sub.None -type Model = Int + val topLeftKey: String = "q" + val topRightKey: String = "w" + val leftKey: String = "a" + val rightKey: String = "s" + val bottomLeftKey: String = "z" + val bottomRightKey: String = "x" + val undoLimit: Int = 25 + val boardTutorialStep: Int = 0 + val roomCodeTutorialStep: Int = 1 + val menuTutorialStep: Int = 2 + val lastTutorialStep: Int = 3 + +final case class Model( + game: Game, + config: Config, + currentLoadState: LoadingState, + currentScenarioType: Option[GameStateScenario], + currentScenarioInput: Option[String], + currentClientSettings: Option[TransientClientSettings], + currentPlayerList: Option[List[CharacterClass]], + currentSelectedFile: Option[(String, Option[(Either[String, Scenario])])], + currentSelectedCell: Option[(Int, Int)], + deadPlayerList: List[CharacterClass], + currentDraggable: Option[MoveablePiece], + connectionStatus: ConnectionStatus, + undoStack: List[GameState], + menuOpen: Boolean, + sideMenuOpen: Boolean, + fullscreen: Boolean, + lockScenario: Boolean, + lockPlayers: Boolean, + lockRoomCode: Boolean, + roomCodeSeed: Option[Int], + keysDown: List[String], + roomCodePassesServerCheck: Boolean, + tooltipTarget: Option[(Element, String)], + contextMenuState: ContextMenu, + contextMenuPosition: (Int, Int), + contextMenuAbsPosition: (Int, Int) +) + +// Double definition +// final case class PieceModel(isDragging: Boolean, coords: Option[(Int, Int)], piece: Piece) + +// Double definition +// final case class BoardOverlayModel(isDragging: Boolean, coords: Option[(Int, Int)], overlay: BoardOverlay) + +final case class TransientClientSettings( + roomCode: (String, String), + summonsColour: String, + showRoomCode: Boolean, + boardOnly: Boolean, + fullscreen: Boolean, + envelopeX: Boolean +) + +enum LoadingState: + case Loaded + case Loading(state: GameStateScenario) + case Failed + +enum ConnectionStatus: + case Connected + case Disconnected + case Reconnecting enum Msg: - case Increment, Decrement + // case LoadedScenarioHttp Seed GameStateScenario (Maybe Game.GameState) Bool (Result Http.Error Scenario) + // case LoadedScenarioJson Seed GameStateScenario (Maybe Game.GameState) Bool (Result Decode.Error Scenario) + // case ReloadScenario + // case ChooseScenarioFile + // case ExtractScenarioFile File + // case LoadScenarioFile String + // case MoveStarted MoveablePiece (Maybe ( DragDrop.EffectAllowed, Decode.Value )) + // case MoveTargetChanged ( Int, Int ) (Maybe ( DragDrop.DropEffect, Decode.Value )) + // case MoveCanceled + // case MoveCompleted + // case TouchStart MoveablePiece + // case TouchMove ( Float, Float ) + // case TouchCanceled + // case TouchEnd ( Float, Float ) + // case CellFromPoint ( Int, Int, Bool ) + // case GameStateUpdated Game.GameState + // case AddOverlay BoardOverlay + // case AddToken BoardOverlay + // case AddHighlight BoardOverlay + // case AddPiece Piece + // case RotateOverlay Int + // case RemoveOverlay BoardOverlay + // case RemovePiece Piece + // case PhasePiece Piece + // case ChangeGameMode GameModeType + // case ChangeAppMode AppModeType + // case RevealRoomMsg (List MapTileRef) ( Int, Int ) + // case ChangeScenario GameStateScenario Bool + // case SelectCell ( Int, Int ) + // case OpenContextMenu + // case ChangeContextMenuState ContextMenu + // case ChangeContextMenuAbsposition ( Int, Int ) + // case ToggleCharacter CharacterClass Bool + // case ToggleBoardOnly Bool + // case ToggleFullscreen Bool + // case ToggleEnvelopeX Bool + // case ToggleMenu + // case ChangePlayerList + // case EnterScenarioType GameStateScenario + // case EnterScenarioNumber String + // case UpdateTutorialStep Int + // case ChangeRoomCodeInputStart String + // case ChangeRoomCodeInputEnd String + // case ChangeShowRoomCode Bool + // case ChangeSummonsColour String + // case ChangeClientSettings (Maybe TransientClientSettings) + // case GameSyncMsg GameSync.Msg + // case PushToUndoStack GameState + // case Undo + // case KeyDown String + // case KeyUp String + // case Paste String + // case VisibilityChanged Visibility + // case PushGameState Bool + // case InitTooltip String String + // case SetTooltip String (Result BrowserDom.Error BrowserDom.Element) + // case ResetTooltip + // case ExitFullscreen () + // case Reconnect + case NoOp From a3a393455a8ecb3067d8477a311b8e421abcd9bf Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 10 Apr 2023 10:32:10 +0100 Subject: [PATCH 23/60] Working through Main --- ui/ui/src/vgb/GameSync.scala | 15 +++ ui/ui/src/vgb/Main.scala | 91 ---------------- ui/ui/src/vgb/Model.scala | 206 +++++++++++++++++++++++++++++++++++ ui/ui/src/vgb/Msg.scala | 78 +++++++++++++ 4 files changed, 299 insertions(+), 91 deletions(-) create mode 100644 ui/ui/src/vgb/GameSync.scala create mode 100644 ui/ui/src/vgb/Model.scala create mode 100644 ui/ui/src/vgb/Msg.scala diff --git a/ui/ui/src/vgb/GameSync.scala b/ui/ui/src/vgb/GameSync.scala new file mode 100644 index 00000000..c585c8cf --- /dev/null +++ b/ui/ui/src/vgb/GameSync.scala @@ -0,0 +1,15 @@ +package vgb + +object GameSync: + + enum Msg: + case ClientDisconnected + case ClientConnected + case UpdateReceived(data: String) + case Disconnected + case Connected + case Reconnecting + case JoinRoom(code: String) + case RoomCodeReceived(code: String) + case RoomCodeInvalid + diff --git a/ui/ui/src/vgb/Main.scala b/ui/ui/src/vgb/Main.scala index c3d5705e..5e3001c2 100644 --- a/ui/ui/src/vgb/Main.scala +++ b/ui/ui/src/vgb/Main.scala @@ -34,35 +34,6 @@ object Main extends TyrianApp[Msg, Model]: val menuTutorialStep: Int = 2 val lastTutorialStep: Int = 3 -final case class Model( - game: Game, - config: Config, - currentLoadState: LoadingState, - currentScenarioType: Option[GameStateScenario], - currentScenarioInput: Option[String], - currentClientSettings: Option[TransientClientSettings], - currentPlayerList: Option[List[CharacterClass]], - currentSelectedFile: Option[(String, Option[(Either[String, Scenario])])], - currentSelectedCell: Option[(Int, Int)], - deadPlayerList: List[CharacterClass], - currentDraggable: Option[MoveablePiece], - connectionStatus: ConnectionStatus, - undoStack: List[GameState], - menuOpen: Boolean, - sideMenuOpen: Boolean, - fullscreen: Boolean, - lockScenario: Boolean, - lockPlayers: Boolean, - lockRoomCode: Boolean, - roomCodeSeed: Option[Int], - keysDown: List[String], - roomCodePassesServerCheck: Boolean, - tooltipTarget: Option[(Element, String)], - contextMenuState: ContextMenu, - contextMenuPosition: (Int, Int), - contextMenuAbsPosition: (Int, Int) -) - // Double definition // final case class PieceModel(isDragging: Boolean, coords: Option[(Int, Int)], piece: Piece) @@ -87,65 +58,3 @@ enum ConnectionStatus: case Connected case Disconnected case Reconnecting - -enum Msg: - // case LoadedScenarioHttp Seed GameStateScenario (Maybe Game.GameState) Bool (Result Http.Error Scenario) - // case LoadedScenarioJson Seed GameStateScenario (Maybe Game.GameState) Bool (Result Decode.Error Scenario) - // case ReloadScenario - // case ChooseScenarioFile - // case ExtractScenarioFile File - // case LoadScenarioFile String - // case MoveStarted MoveablePiece (Maybe ( DragDrop.EffectAllowed, Decode.Value )) - // case MoveTargetChanged ( Int, Int ) (Maybe ( DragDrop.DropEffect, Decode.Value )) - // case MoveCanceled - // case MoveCompleted - // case TouchStart MoveablePiece - // case TouchMove ( Float, Float ) - // case TouchCanceled - // case TouchEnd ( Float, Float ) - // case CellFromPoint ( Int, Int, Bool ) - // case GameStateUpdated Game.GameState - // case AddOverlay BoardOverlay - // case AddToken BoardOverlay - // case AddHighlight BoardOverlay - // case AddPiece Piece - // case RotateOverlay Int - // case RemoveOverlay BoardOverlay - // case RemovePiece Piece - // case PhasePiece Piece - // case ChangeGameMode GameModeType - // case ChangeAppMode AppModeType - // case RevealRoomMsg (List MapTileRef) ( Int, Int ) - // case ChangeScenario GameStateScenario Bool - // case SelectCell ( Int, Int ) - // case OpenContextMenu - // case ChangeContextMenuState ContextMenu - // case ChangeContextMenuAbsposition ( Int, Int ) - // case ToggleCharacter CharacterClass Bool - // case ToggleBoardOnly Bool - // case ToggleFullscreen Bool - // case ToggleEnvelopeX Bool - // case ToggleMenu - // case ChangePlayerList - // case EnterScenarioType GameStateScenario - // case EnterScenarioNumber String - // case UpdateTutorialStep Int - // case ChangeRoomCodeInputStart String - // case ChangeRoomCodeInputEnd String - // case ChangeShowRoomCode Bool - // case ChangeSummonsColour String - // case ChangeClientSettings (Maybe TransientClientSettings) - // case GameSyncMsg GameSync.Msg - // case PushToUndoStack GameState - // case Undo - // case KeyDown String - // case KeyUp String - // case Paste String - // case VisibilityChanged Visibility - // case PushGameState Bool - // case InitTooltip String String - // case SetTooltip String (Result BrowserDom.Error BrowserDom.Element) - // case ResetTooltip - // case ExitFullscreen () - // case Reconnect - case NoOp diff --git a/ui/ui/src/vgb/Model.scala b/ui/ui/src/vgb/Model.scala new file mode 100644 index 00000000..7f77aa37 --- /dev/null +++ b/ui/ui/src/vgb/Model.scala @@ -0,0 +1,206 @@ +package vgb + +import org.scalajs.dom.Element + +final case class Model( + game: Game, + config: Config, + currentLoadState: LoadingState, + currentScenarioType: Option[GameStateScenario], + currentScenarioInput: Option[String], + currentClientSettings: Option[TransientClientSettings], + currentPlayerList: Option[List[CharacterClass]], + currentSelectedFile: Option[(String, Option[(Either[String, Scenario])])], + currentSelectedCell: Option[(Int, Int)], + deadPlayerList: List[CharacterClass], + currentDraggable: Option[MoveablePiece], + connectionStatus: ConnectionStatus, + undoStack: List[GameState], + menuOpen: Boolean, + sideMenuOpen: Boolean, + fullscreen: Boolean, + lockScenario: Boolean, + lockPlayers: Boolean, + lockRoomCode: Boolean, + roomCodeSeed: Option[Int], + keysDown: List[String], + roomCodePassesServerCheck: Boolean, + tooltipTarget: Option[(Element, String)], + contextMenuState: ContextMenu, + contextMenuPosition: (Int, Int), + contextMenuAbsPosition: (Int, Int) +) + +object Model: + + init : ( Maybe Decode.Value, Maybe Decode.Value, Int ) -> ( Model, Cmd Msg ) + init ( oldState, maybeOverrides, seed ) = + let + overrides = + case maybeOverrides of + Just o -> + case loadOverrides o of + Ok ov -> + ov + + _ -> + emptyOverrides + + Nothing -> + emptyOverrides + + ( gs, initConfig ) = + case oldState of + Just s -> + case loadFromStorage s of + Ok ( g, c ) -> + ( g + , { c + | roomCode = + case overrides.initRoomCodeSeed of + Just _ -> + Nothing + + Nothing -> + c.roomCode + , campaignTracker = + case overrides.campaignTracker of + Just t -> + Just t + + Nothing -> + c.campaignTracker + } + ) + + Err _ -> + AppStorage.empty + + Nothing -> + AppStorage.empty + + forceScenarioRefresh = + (case overrides.initPlayers of + Nothing -> + List.length gs.players == 0 + + Just p -> + (List.length p > 0 && p /= gs.players) + || (List.length gs.players == 0) + ) + || (case overrides.initScenario of + Just newScenario -> + case gs.scenario of + InbuiltScenario Gloomhaven oldScenario -> + newScenario /= oldScenario + + _ -> + True + + Nothing -> + False + ) + + initGameState = + { gs + | updateCount = 0 + , players = + case overrides.initPlayers of + Just p -> + if List.length p > 0 then + p + + else + gs.players + + Nothing -> + gs.players + , roomCode = + case overrides.initRoomCodeSeed of + Just _ -> + "" + + Nothing -> + gs.roomCode + } + + initGame = + Game.empty + + initScenario = + case overrides.initScenario of + Just i -> + InbuiltScenario Gloomhaven i + + Nothing -> + initGameState.scenario + + model = + Model + { initGame | state = initGameState } + initConfig + (Loading initGameState.scenario) + Nothing + Nothing + Nothing + Nothing + Nothing + Nothing + (getDeadPlayers initGameState) + Nothing + Disconnected + [] + False + False + False + overrides.lockScenario + overrides.lockPlayers + overrides.lockRoomCode + overrides.initRoomCodeSeed + [] + True + Nothing + Closed + ( 0, 0 ) + ( 0, 0 ) + in + case initScenario of + InbuiltScenario _ _ -> + ( model + , Cmd.batch + [ connectToServer + , loadScenarioById + initScenario + (LoadedScenarioHttp + (Random.initialSeed seed) + initScenario + (if forceScenarioRefresh then + Nothing + + else + Just initGameState + ) + False + ) + ] + ) + + CustomScenario s -> + let + ( m, msg ) = + update + (LoadedScenarioJson + (Random.initialSeed seed) + initScenario + (if forceScenarioRefresh then + Nothing + + else + Just initGameState + ) + False + (decodeString decodeScenario s) + ) + model + in + ( m, Cmd.batch [ connectToServer, msg ] ) diff --git a/ui/ui/src/vgb/Msg.scala b/ui/ui/src/vgb/Msg.scala new file mode 100644 index 00000000..dd0d2d63 --- /dev/null +++ b/ui/ui/src/vgb/Msg.scala @@ -0,0 +1,78 @@ +package vgb + +import org.scalajs.dom.Element +import org.scalajs.dom.PageVisibility + +enum Msg: + case LoadedScenarioHttp( + seed: Long, + scenario: GameStateScenario, + state: Option[GameState], + addToUndo: Boolean, + loadedScenario: Either[String, Scenario] + ) + case LoadedScenarioJson( + seed: Long, + scenario: GameStateScenario, + state: Option[GameState], + addToUndo: Boolean, + loadedScenario: Either[String, Scenario] + ) + case ReloadScenario + case ChooseScenarioFile + case ExtractScenarioFile(file: String) + case LoadScenarioFile(file: String) + case MoveStarted(piece: MoveablePiece, result: Option[(String, String)]) + case MoveTargetChanged(target: (Int, Int), result: Option[(String, String)]) + case MoveCanceled + case MoveCompleted + case TouchStart(piece: MoveablePiece) + case TouchMove(position: (Float, Float)) + case TouchCanceled + case TouchEnd(position: (Float, Float)) + case CellFromPoint(at: (Int, Int, Boolean)) + case GameStateUpdated(state: GameState) + case AddOverlay(overlay: BoardOverlay) + case AddToken(overlay: BoardOverlay) + case AddHighlight(overlay: BoardOverlay) + case AddPiece(piece: Piece) + case RotateOverlay(turns: Int) + case RemoveOverlay(overlay: BoardOverlay) + case RemovePiece(piece: Piece) + case PhasePiece(piece: Piece) + case ChangeGameMode(mode: GameModeType) + case ChangeAppMode(mode: AppModeType) + case RevealRoomMsg(refs: List[MapTileRef], position: (Int, Int)) + case ChangeScenario(newScenario: GameStateScenario, forceReload: Boolean) + case SelectCell(cell: (Int, Int)) + case OpenContextMenu + case ChangeContextMenuState(state: ContextMenu) + case ChangeContextMenuAbsposition(position: (Int, Int)) + case ToggleCharacter(character: CharacterClass, enabled: Boolean) + case ToggleBoardOnly(boardOnly: Boolean) + case ToggleFullscreen(fullscreen: Boolean) + case ToggleEnvelopeX(envelopeX: Boolean) + case ToggleMenu + case ChangePlayerList + case EnterScenarioType(scenario: GameStateScenario) + case EnterScenarioNumber(id: String) + case UpdateTutorialStep(step: Int) + case ChangeRoomCodeInputStart(id: String) + case ChangeRoomCodeInputEnd(id: String) + case ChangeShowRoomCode(visible: Boolean) + case ChangeSummonsColour(colour: String) + case ChangeClientSettings(settings: Option[TransientClientSettings]) + case GameSyncMsg(msg: GameSync.Msg) + case PushToUndoStack(state: GameState) + case Undo + case KeyDown(key: String) + case KeyUp(key: String) + case Paste(value: String) + case VisibilityChanged(visibility: PageVisibility) + case PushGameState(addToUndo: Boolean) + case InitTooltip(id: String, text: String) + case SetTooltip(id: String, element: Either[String, Element]) + case ResetTooltip + case ExitFullscreen() + case Reconnect + case NoOp From 54206f5f4a2689712679cfb26de882192f5b31c8 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Mon, 10 Apr 2023 10:55:49 +0100 Subject: [PATCH 24/60] Initial function ported, does not compile --- ui/ui/src/vgb/Model.scala | 328 ++++++++++++++++++-------------------- 1 file changed, 159 insertions(+), 169 deletions(-) diff --git a/ui/ui/src/vgb/Model.scala b/ui/ui/src/vgb/Model.scala index 7f77aa37..e10170a1 100644 --- a/ui/ui/src/vgb/Model.scala +++ b/ui/ui/src/vgb/Model.scala @@ -1,6 +1,8 @@ package vgb import org.scalajs.dom.Element +import cats.effect.IO +import tyrian.* final case class Model( game: Game, @@ -33,174 +35,162 @@ final case class Model( object Model: - init : ( Maybe Decode.Value, Maybe Decode.Value, Int ) -> ( Model, Cmd Msg ) - init ( oldState, maybeOverrides, seed ) = - let - overrides = - case maybeOverrides of - Just o -> - case loadOverrides o of - Ok ov -> - ov - - _ -> - emptyOverrides - - Nothing -> - emptyOverrides - - ( gs, initConfig ) = - case oldState of - Just s -> - case loadFromStorage s of - Ok ( g, c ) -> - ( g - , { c - | roomCode = - case overrides.initRoomCodeSeed of - Just _ -> - Nothing - - Nothing -> - c.roomCode - , campaignTracker = - case overrides.campaignTracker of - Just t -> - Just t - - Nothing -> - c.campaignTracker - } - ) - - Err _ -> - AppStorage.empty - - Nothing -> - AppStorage.empty - - forceScenarioRefresh = - (case overrides.initPlayers of - Nothing -> - List.length gs.players == 0 - - Just p -> - (List.length p > 0 && p /= gs.players) - || (List.length gs.players == 0) - ) - || (case overrides.initScenario of - Just newScenario -> - case gs.scenario of - InbuiltScenario Gloomhaven oldScenario -> - newScenario /= oldScenario - - _ -> - True - - Nothing -> - False - ) - - initGameState = - { gs - | updateCount = 0 - , players = - case overrides.initPlayers of - Just p -> - if List.length p > 0 then - p - - else - gs.players - - Nothing -> - gs.players - , roomCode = - case overrides.initRoomCodeSeed of - Just _ -> - "" - - Nothing -> - gs.roomCode - } - - initGame = - Game.empty - - initScenario = - case overrides.initScenario of - Just i -> - InbuiltScenario Gloomhaven i - - Nothing -> - initGameState.scenario - - model = - Model - { initGame | state = initGameState } - initConfig - (Loading initGameState.scenario) - Nothing - Nothing - Nothing - Nothing - Nothing - Nothing - (getDeadPlayers initGameState) - Nothing - Disconnected - [] - False - False - False - overrides.lockScenario - overrides.lockPlayers - overrides.lockRoomCode - overrides.initRoomCodeSeed - [] - True - Nothing - Closed - ( 0, 0 ) - ( 0, 0 ) - in - case initScenario of - InbuiltScenario _ _ -> - ( model - , Cmd.batch - [ connectToServer - , loadScenarioById - initScenario - (LoadedScenarioHttp - (Random.initialSeed seed) - initScenario - (if forceScenarioRefresh then - Nothing - - else - Just initGameState - ) - False - ) - ] + def init(oldState: Option[String], maybeOverrides: Option[String], seed: Int): (Model, Cmd[IO, Msg]) = { + val overrides = + maybeOverrides match + case Some(o) => + loadOverrides(o) match + case Ok(ov) => + ov + + case _ => + emptyOverrides + + case None => + emptyOverrides + + val (gs, initConfig) = + oldState match + case Some(s) => + loadFromStorage(s) match + case Ok((g, c)) => + ( + g, + c.copy( + roomCode = overrides.initRoomCodeSeed match { + case Some(_) => + Nothing + + case None => + c.roomCode + }, + campaignTracker = overrides.campaignTracker match { + case Some(t) => + Option(t) + + case None => + c.campaignTracker + } + ) ) - CustomScenario s -> - let - ( m, msg ) = - update - (LoadedScenarioJson - (Random.initialSeed seed) - initScenario - (if forceScenarioRefresh then - Nothing - - else - Just initGameState - ) - False - (decodeString decodeScenario s) - ) - model - in - ( m, Cmd.batch [ connectToServer, msg ] ) + case Err(_) => + AppStorage.empty + + case None => + AppStorage.empty + + val forceScenarioRefresh = + (overrides.initPlayers match + case None => + gs.players.length == 0 + + case Some(p) => + (p.length > 0 && p /= gs.players) || (gs.players.length == 0) + ) + || (overrides.initScenario match + case Some(newScenario) => + gs.scenario match + case InbuiltScenario(Gloomhaven, oldScenario) => + newScenario /= oldScenario + + case _ => + true + + case None => + false + ) + + val initGameState = + gs.copy( + updateCount = 0, + players = overrides.initPlayers match + case Some(p) => + if p.length > 0 then p else gs.players + + case None => + gs.players + , + roomCode = overrides.initRoomCodeSeed match + case Some(_) => + "" + + case None => + gs.roomCode + ) + + val initGame = + Game.empty + + val initScenario = + overrides.initScenario match + case Some(i) => + InbuiltScenario(Gloomhaven, i) + + case None => + initGameState.scenario + + val model = + Model( + initGame.copy(state = initGameState), + initConfig, + Loading(initGameState.scenario), + None, + None, + None, + None, + None, + None, + getDeadPlayers(initGameState), + Nothing, + Disconnected, + Nil, + false, + false, + false, + overrides.lockScenario, + overrides.lockPlayers, + overrides.lockRoomCode, + overrides.initRoomCodeSeed, + Nil, + true, + None, + Closed, + (0, 0), + (0, 0) + ) + + initScenario match + case InbuiltScenario(_, _) => + ( + model, + Cmd.Batch( + connectToServer, + loadScenarioById( + initScenario, + LoadedScenarioHttp( + Random.initialSeed(seed), + initScenario, + if forceScenarioRefresh then None + else Option(initGameState), + false + ) + ) + ) + ) + + case CustomScenario(s) => + val (m, msg) = + update( + LoadedScenarioJson( + Random.initialSeed(seed), + initScenario, + if forceScenarioRefresh then None else Option(initGameState), + false, + (decodeString decodeScenario s) + ), + model + ) + + (m, Cmd.Batch(connectToServer, msg)) + } From 2a889d1543c9ff56d57703c326a2db2012246039 Mon Sep 17 00:00:00 2001 From: David North Date: Fri, 28 Apr 2023 21:36:48 +0100 Subject: [PATCH 25/60] Adds a HTML page that can be used for scaling images and extracting JSON data --- tooling.html | 1642 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1642 insertions(+) create mode 100644 tooling.html diff --git a/tooling.html b/tooling.html new file mode 100644 index 00000000..b5005322 --- /dev/null +++ b/tooling.html @@ -0,0 +1,1642 @@ + + + + + + + + + + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + From 9e7e30137ccfd42c3d5b9b71c265c3e0343e05cd Mon Sep 17 00:00:00 2001 From: David North Date: Tue, 2 May 2023 20:55:55 +0100 Subject: [PATCH 26/60] Starts to build out the Indigo implementation Just displays hexes on the screen at the moment --- VirtualGloomhavenBoard/Indigo/.mill-version | 1 + VirtualGloomhavenBoard/Indigo/.scalafix.conf | 26 + VirtualGloomhavenBoard/Indigo/.scalafmt.conf | 6 + VirtualGloomhavenBoard/Indigo/build.sc | 82 + .../Indigo/gamedata/gameData.sc | 4 + VirtualGloomhavenBoard/Indigo/package.json | 33 + .../vgb-common/src/vgb/common/CommonMsg.scala | 12 + .../Indigo/vgb-game/src/vgb/game/Main.scala | 101 + .../src/vgb/game/models/GameModel.scala | 8 + .../src/vgb/game/models/GameViewModel.scala | 8 + .../game/models/components/HexComponent.scala | 86 + .../src/vgb/game/scenes/CreatorScene.scala | 63 + .../Indigo/vgb-ui/src/vgb/ui/Main.scala | 59 + .../Indigo/vgb-ui/src/vgb/ui/Model.scala | 20 + .../wwwroot}/browserconfig.xml | 2 +- .../wwwroot}/fonts/PirataOne-Gloomhaven.eot | Bin .../wwwroot}/fonts/PirataOne-Gloomhaven.otf | Bin .../wwwroot}/fonts/PirataOne-Gloomhaven.svg | 0 .../wwwroot}/fonts/PirataOne-Gloomhaven.ttf | Bin .../wwwroot}/fonts/PirataOne-Gloomhaven.woff | Bin .../wwwroot}/fonts/PirataOne-Gloomhaven.woff2 | Bin .../img/favicons/android-icon-144x144.png | Bin .../img/favicons/android-icon-192x192.png | Bin .../img/favicons/android-icon-36x36.png | Bin .../img/favicons/android-icon-48x48.png | Bin .../img/favicons/android-icon-72x72.png | Bin .../img/favicons/android-icon-96x96.png | Bin .../wwwroot}/img/favicons/app.ico | Bin .../img/favicons/apple-icon-114x114.png | Bin .../img/favicons/apple-icon-120x120.png | Bin .../img/favicons/apple-icon-144x144.png | Bin .../img/favicons/apple-icon-152x152.png | Bin .../img/favicons/apple-icon-180x180.png | Bin .../img/favicons/apple-icon-57x57.png | Bin .../img/favicons/apple-icon-60x60.png | Bin .../img/favicons/apple-icon-72x72.png | Bin .../img/favicons/apple-icon-76x76.png | Bin .../img/favicons/apple-icon-precomposed.png | Bin .../wwwroot}/img/favicons/apple-icon.png | Bin .../wwwroot}/img/favicons/favicon-16x16.png | Bin .../wwwroot}/img/favicons/favicon-32x32.png | Bin .../wwwroot}/img/favicons/favicon-96x96.png | Bin .../wwwroot}/img/favicons/favicon.ico | Bin .../wwwroot}/img/favicons/ms-icon-144x144.png | Bin .../wwwroot}/img/favicons/ms-icon-150x150.png | Bin .../wwwroot}/img/favicons/ms-icon-310x310.png | Bin .../wwwroot}/img/favicons/ms-icon-70x70.png | Bin .../Indigo/wwwroot/index.html | 43 + .../Indigo/wwwroot/js/app.js | 247 ++ .../{assets => Indigo/wwwroot}/manifest.json | 0 VirtualGloomhavenBoard/Indigo/yarn.lock | 2097 +++++++++++++++++ 51 files changed, 2897 insertions(+), 1 deletion(-) create mode 100644 VirtualGloomhavenBoard/Indigo/.mill-version create mode 100644 VirtualGloomhavenBoard/Indigo/.scalafix.conf create mode 100644 VirtualGloomhavenBoard/Indigo/.scalafmt.conf create mode 100644 VirtualGloomhavenBoard/Indigo/build.sc create mode 100644 VirtualGloomhavenBoard/Indigo/gamedata/gameData.sc create mode 100644 VirtualGloomhavenBoard/Indigo/package.json create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameModel.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameViewModel.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Model.scala rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/browserconfig.xml (91%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/fonts/PirataOne-Gloomhaven.eot (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/fonts/PirataOne-Gloomhaven.otf (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/fonts/PirataOne-Gloomhaven.svg (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/fonts/PirataOne-Gloomhaven.ttf (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/fonts/PirataOne-Gloomhaven.woff (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/fonts/PirataOne-Gloomhaven.woff2 (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/android-icon-144x144.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/android-icon-192x192.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/android-icon-36x36.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/android-icon-48x48.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/android-icon-72x72.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/android-icon-96x96.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/app.ico (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-114x114.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-120x120.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-144x144.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-152x152.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-180x180.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-57x57.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-60x60.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-72x72.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-76x76.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon-precomposed.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/apple-icon.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/favicon-16x16.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/favicon-32x32.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/favicon-96x96.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/favicon.ico (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/ms-icon-144x144.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/ms-icon-150x150.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/ms-icon-310x310.png (100%) rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/img/favicons/ms-icon-70x70.png (100%) create mode 100644 VirtualGloomhavenBoard/Indigo/wwwroot/index.html create mode 100644 VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js rename VirtualGloomhavenBoard/{assets => Indigo/wwwroot}/manifest.json (100%) create mode 100644 VirtualGloomhavenBoard/Indigo/yarn.lock diff --git a/VirtualGloomhavenBoard/Indigo/.mill-version b/VirtualGloomhavenBoard/Indigo/.mill-version new file mode 100644 index 00000000..70016a7c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/.mill-version @@ -0,0 +1 @@ +0.10.12 diff --git a/VirtualGloomhavenBoard/Indigo/.scalafix.conf b/VirtualGloomhavenBoard/Indigo/.scalafix.conf new file mode 100644 index 00000000..f55b7ca7 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/.scalafix.conf @@ -0,0 +1,26 @@ +rules = [ + DisableSyntax, + OrganizeImports +] + +OrganizeImports { + removeUnused = false +} + +DisableSyntax { + noVars = true + noThrows = true + noNulls = true + noReturns = true + noWhileLoops = true + noAsInstanceOf = false # Doesn't seem to work correctly + noIsInstanceOf = false # Doesn't seem to work correctly + noXml = true + noDefaultArgs = true + noFinalVal = true + noFinalize = true + noValPatterns = true + # noUniversalEquality = false # handled by scala 3 + # noUniversalEqualityMessage = "== and != are unsafe since they allow comparing two unrelated types" + # regex = [] +} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/Indigo/.scalafmt.conf b/VirtualGloomhavenBoard/Indigo/.scalafmt.conf new file mode 100644 index 00000000..55f2ba2b --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/.scalafmt.conf @@ -0,0 +1,6 @@ +version = 3.5.8 +runner.dialect = scala3 +style = defaultWithAlign +maxColumn = 120 +rewrite.rules = [RedundantBraces,RedundantParens,PreferCurlyFors] +danglingParentheses.preset = true diff --git a/VirtualGloomhavenBoard/Indigo/build.sc b/VirtualGloomhavenBoard/Indigo/build.sc new file mode 100644 index 00000000..a3cb2a18 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/build.sc @@ -0,0 +1,82 @@ +import $ivy.`com.lihaoyi::mill-contrib-bloop:$MILL_VERSION` +import mill._ +import mill.scalalib._ +import mill.scalajslib._ +import mill.scalajslib.api._ +import $file.gamedata.gameData + +import $ivy.`io.github.davidgregory084::mill-tpolecat::0.3.2` +import io.github.davidgregory084.TpolecatModule + +object `vgb-common` extends VgbModule + +object `vgb-game` extends VgbModule { + override def moduleDeps = Seq(`vgb-common`) + + // generatedSources is a list of paths to source files. + // It is called on compile, so by hooking in our function + // our code is re-generated on compilation. + override def generatedSources: T[Seq[PathRef]] = T { + // Set a working directory inside the `out` dir + val wd = os.pwd / "out" / "gamedata" + // Make sure it exists + os.makeDir.all(wd) + + gameData.CodeGen + .generate() + .map(d => + d match { + case (file, data) => + // Write to the file + os.write.over( + wd / s"""${file.capitalize}.scala""", + s"""/* This file is auto-generated. Please do not modify it manually */ + |${data}""".stripMargin.trim + ) + } + ) + + // Call out code gen function and concat the paths onto + // the standard path list. + Seq(PathRef(wd)) ++ super.generatedSources() + } +} + +object `vgb-ui` extends VgbModule { + override def moduleDeps = Seq(`vgb-common`, `vgb-game`) + + def build() = + T.command { + T { + compile() + fastOpt() + } + } +} + +trait VgbModule extends ScalaJSModule with TpolecatModule { + def scalaVersion = "3.2.2" + def scalaJSVersion = "1.13.1" + + val indigoVersion = "0.14.0" + val tyrianVersion = "0.6.1" + + def ivyDeps = + Agg( + ivy"io.indigoengine::tyrian-io::$tyrianVersion", + ivy"io.indigoengine::tyrian-indigo-bridge::$tyrianVersion", + ivy"io.indigoengine::indigo-json-circe::$indigoVersion", + ivy"io.indigoengine::indigo::$indigoVersion", + ivy"io.indigoengine::indigo-extras::$indigoVersion", + ivy"org.scala-js:scalajs-java-securerandom_sjs1_2.13:1.0.0" + ) + + override def moduleKind = T(mill.scalajslib.api.ModuleKind.CommonJSModule) + + object test extends Tests with TestModule.Munit { + + def ivyDeps = Agg( + ivy"org.scalameta::munit::1.0.0-M7" + ) + } +} diff --git a/VirtualGloomhavenBoard/Indigo/gamedata/gameData.sc b/VirtualGloomhavenBoard/Indigo/gamedata/gameData.sc new file mode 100644 index 00000000..2400806a --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/gamedata/gameData.sc @@ -0,0 +1,4 @@ +object CodeGen { + def generate(): List[(String, String)] = + List.empty +} diff --git a/VirtualGloomhavenBoard/Indigo/package.json b/VirtualGloomhavenBoard/Indigo/package.json new file mode 100644 index 00000000..7c6a051d --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/package.json @@ -0,0 +1,33 @@ +{ + "scripts": { + "start": "parcel wwwroot/index.html --open --dist-dir build --log-level info --no-cache", + "build": "parcel build wwwroot/index.html --dist-dir build --log-level info --no-cache" + }, + "dependencies": { + "@microsoft/signalr": "^6.0.2", + "@microsoft/signalr-protocol-msgpack": "^6.0.2" + }, + "devDependencies": { + "@parcel/packager-raw-url": "2.8.3", + "@parcel/transformer-sass": "^2.8.3", + "@parcel/transformer-webmanifest": "2.8.3", + "buffer": "^5.7.1", + "crypto-browserify": "^3.12.0", + "events": "^3.3.0", + "parcel": "^2.8.3", + "parcel-reporter-static-files-copy": "^1.5.0", + "process": "^0.11.10", + "stream-browserify": "^3.0.0" + }, + "staticFiles": { + "staticPath": "wwwroot/", + "watcherGlob": "**" + }, + "alias": { + "assert": false, + "console": false, + "crypto": false, + "buffer": false, + "stream": false + } +} diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala new file mode 100644 index 00000000..d54cdcfb --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala @@ -0,0 +1,12 @@ +package vgb.common + +/** A message from the VGB app + */ +trait GloomhavenMsg +object GloomhavenMsg: + given CanEqual[GloomhavenMsg, GloomhavenMsg] = CanEqual.derived + + /** General messages that can be used across many scenes + */ +enum GeneralMsgType extends GloomhavenMsg: + case Empty diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala new file mode 100644 index 00000000..ebfd3394 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala @@ -0,0 +1,101 @@ +package vgb.game + +import cats.effect.IO +import indigo.* +import indigo.scenes.* +import tyrian.TyrianSubSystem +import vgb.common.* +import vgb.game.scenes.* +import vgb.game.models.GameModel +import vgb.game.models.GameViewModel +import vgb.game.models.components.HexComponent + +final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) + extends IndigoGame[Size, Size, GameModel, GameViewModel] { + + val magnification = 1 + + def initialScene(bootData: Size): Option[SceneName] = + None + + def scenes(bootData: Size): NonEmptyList[Scene[Size, GameModel, GameViewModel]] = + NonEmptyList(CreatorScene(tyrianSubSystem)) + + val eventFilters: EventFilters = + EventFilters.AllowAll + + def boot(flags: Map[String, String]): Outcome[BootResult[Size]] = + val gameViewport = + (flags.get("width"), flags.get("height")) match { + case (Some(w), Some(h)) => + GameViewport(w.toInt, h.toInt) + + case _ => + GameViewport(300, 300) + } + + Outcome( + BootResult( + GameConfig.default + .withMagnification(magnification) + .withClearColor(RGBA.White) + .withViewport(gameViewport), + gameViewport.size / magnification + ) + .withSubSystems(tyrianSubSystem) + ) + + def setup( + bootData: Size, + assetCollection: AssetCollection, + dice: Dice + ): Outcome[Startup[Size]] = + Outcome(Startup.Success(bootData)) + + def initialModel(startupData: Size): Outcome[GameModel] = + Outcome(GameModel(startupData)) + + def initialViewModel(startupData: Size, model: GameModel): Outcome[GameViewModel] = + Outcome(GameViewModel(startupData)) + + def updateModel( + context: FrameContext[Size], + model: GameModel + ): GlobalEvent => Outcome[GameModel] = { + case tyrianSubSystem.TyrianEvent.Receive(msg) => + msg match { + case _ => + Outcome(model) + } + case _ => + Outcome(model) + } + + def updateViewModel( + context: FrameContext[Size], + model: GameModel, + viewModel: GameViewModel + ): GlobalEvent => Outcome[GameViewModel] = + case MouseEvent.Move(p) => + IndigoLogger.consoleLog(HexComponent.screenPosToOddRow(p).toString) + Outcome(viewModel) + case _ => Outcome(viewModel) + + def present( + context: FrameContext[Size], + model: GameModel, + viewModel: GameViewModel + ): Outcome[SceneUpdateFragment] = + Outcome( + SceneUpdateFragment( + Batch.fromArray( + (0 until 10).toArray + .map(x => + (0 until 10).toArray + .map(y => HexComponent.render(Point(x, y))) + ) + .flatten + ) + ) + ) +} diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameModel.scala new file mode 100644 index 00000000..56781a0b --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameModel.scala @@ -0,0 +1,8 @@ +package vgb.game.models + +import indigo.* + +final case class GameModel() + +object GameModel: + def apply(startupData: Size): GameModel = GameModel() diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameViewModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameViewModel.scala new file mode 100644 index 00000000..1ac1a8e2 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameViewModel.scala @@ -0,0 +1,8 @@ +package vgb.game.models + +import indigo.* + +final case class GameViewModel() + +object GameViewModel: + def apply(startupData: Size): GameViewModel = GameViewModel() diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala new file mode 100644 index 00000000..a91479d4 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala @@ -0,0 +1,86 @@ +package vgb.game.models.components + +import indigo.* +import indigoextras.geometry.Vertex +import indigo.shared.scenegraph.Shape.Line +import indigo.shared.scenegraph.Shape.Polygon +import indigo.shared.scenegraph.Shape.Circle + +object HexComponent: + private val sqrtThree = Math.sqrt(3) + private val baseQ = sqrtThree / 3 + private val oneOver3 = 1.0 / 3 + private val twoOver3 = 2.0 / 3 + private val threeOver2 = 3.0 / 2 + private val size = 90 + private val halfSize = size * 0.5 + private val quarterSize = size * 0.25 + private val rectWidth = sqrtThree * halfSize + private val halfWidth = rectWidth * 0.5 + private val polygon = Polygon( + Batch( + Point(0, -Math.floor(halfSize).toInt), // Top tip + Point(Math.floor(halfWidth).toInt, -Math.floor(quarterSize).toInt), // Right-top corner of rectangle + Point(Math.floor(halfWidth).toInt, Math.ceil(quarterSize).toInt), // Right-bottom corner of rectangle + Point(0, Math.ceil(halfSize).toInt), // Bottom tip + Point(-Math.ceil(halfWidth).toInt, Math.ceil(quarterSize).toInt), // Left-bottom corner of rectangle, + Point(-Math.ceil(halfWidth).toInt, -Math.floor(quarterSize).toInt) // Left-top corner of rectangle + ), + Fill.Color(RGBA.Green), + Stroke.Black + ) + + def render(position: Point): Group = + Group( + polygon + // 0,0 position is the top left + .moveTo(oddRowToScreenPos(position)) + // For screen position to co-ordinates to work correctly, 0,0 needs to be centre + .moveBy((polygon.size.width * -0.5).toInt, (polygon.size.height * -0.5).toInt), + Circle(oddRowToScreenPos(position), 2, Fill.Color(RGBA.Red)) + ) + + def screenPosToCube(pos: Point) = { + val q = (baseQ * pos.x.toDouble - (oneOver3 * pos.y.toDouble)) / halfSize.toDouble + val r = (twoOver3 * pos.y.toDouble) / halfSize.toDouble + cubeRound(axialToCube(Vector2(q, r))) + } + + def screenPosToOddRow(pos: Point) = + cubeToOddRow(screenPosToCube(pos)) + + def axialToScreenPos(pos: Vector2) = + Point( + (halfSize * (sqrtThree * pos.x + (sqrtThree * 0.5) * pos.y)).toInt, + (halfSize * threeOver2 * pos.y).toInt + ) + + def oddRowToScreenPos(pos: Point) = + axialToScreenPos(oddRowToAxial(pos)) + + def oddRowToAxial(pos: Point) = + Vector2( + pos.x - (pos.y - (pos.y.toInt & 1)) * 0.5, + pos.y + ) + + def cubeToOddRow(pos: Vector3) = + Vector2(pos.x + (pos.y - (pos.y.toInt & 1)) * 0.5, pos.y) + + def axialToCube(pos: Vector2) = + Vector3(pos.x, pos.y, -pos.x - pos.y) + + def cubeRound(pos: Vector3) = pos match { + case Vector3(fracQ, fracR, fracS) => + val q = Math.round(fracQ).toDouble + val r = Math.round(fracR).toDouble + val s = Math.round(fracS).toDouble + + val qDiff = Math.abs(q - fracQ) + val rDiff = Math.abs(r - fracR) + val sDiff = Math.abs(s - fracS) + + if qDiff > rDiff && qDiff > sDiff then Vector3(-r - s, r, s) + else if rDiff > sDiff then Vector3(q, -q - s, s) + else Vector3(q, r, -q - r) + } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala new file mode 100644 index 00000000..8fc5e3dd --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -0,0 +1,63 @@ +package vgb.game.scenes + +import cats.effect.IO +import indigo.* +import indigo.scenes.* +import tyrian.TyrianSubSystem +import vgb.common.* +import vgb.game.models.GameModel +import vgb.game.models.GameViewModel + +/** Placeholder scene for the space station + * + * @param tyrianSubSystem + */ +final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) + extends Scene[Size, GameModel, GameViewModel]: + + type SceneModel = GameModel + type SceneViewModel = GameViewModel + + val name: SceneName = SceneName("creator-scene") + + val modelLens: Lens[GameModel, SceneModel] = + Lens( + (gameModel: GameModel) => gameModel, + (gameModel: GameModel, model: SceneModel) => model + ) + + val viewModelLens: Lens[GameViewModel, SceneViewModel] = + Lens( + (gameViewModel: GameViewModel) => gameViewModel, + (gameViewModel: GameViewModel, viewModel: SceneViewModel) => viewModel + ) + + val eventFilters: EventFilters = + EventFilters.AllowAll + + val subSystems: Set[SubSystem] = + Set(tyrianSubSystem) + + def updateModel( + context: SceneContext[Size], + model: SceneModel + ): GlobalEvent => Outcome[SceneModel] = { case _ => + Outcome(model) + } + + def updateViewModel( + context: SceneContext[Size], + model: SceneModel, + viewModel: SceneViewModel + ): GlobalEvent => Outcome[SceneViewModel] = { case _ => + Outcome(viewModel) + } + + def present( + context: SceneContext[Size], + model: SceneModel, + viewModel: SceneViewModel + ): Outcome[SceneUpdateFragment] = + Outcome( + SceneUpdateFragment.empty + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala new file mode 100644 index 00000000..a6881df2 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala @@ -0,0 +1,59 @@ +package vgb.ui + +import cats.effect.IO +import tyrian.* +import tyrian.Html.* +import org.scalajs.dom.document +import vgb.game.{Main => VgbGame} +import vgb.common.* + +import scala.scalajs.js.annotation.* + +enum Msg: + case IndigoReceive(msg: GloomhavenMsg) extends Msg + case IndigoSend(msg: GloomhavenMsg) extends Msg + case StartIndigo extends Msg + +@JSExportTopLevel("TyrianApp") +object Main extends TyrianApp[Msg, Model]: + val gameDivId = "map-container" + + def init(flags: Map[String, String]): (Model, Cmd[IO, Msg]) = + (Model(), Cmd.Emit(Msg.StartIndigo)) + + def update(model: Model): Msg => (Model, Cmd[IO, Msg]) = + case Msg.IndigoReceive(msg) => + updateIndigoReceive(msg, model) + case Msg.IndigoSend(msg) => + (model, model.bridge.publish(IndigoGameId(gameDivId), msg)) + case Msg.StartIndigo => + ( + model, + Cmd.SideEffect { + VgbGame(model.bridge.subSystem(IndigoGameId(gameDivId))) + .launch( + gameDivId, + "width" -> "1620", + "height" -> "800" + ) + } + ) + + def view(model: Model): Html[Msg] = + div(`class` := "main")( + div(id := "map-container")() + ) + + def subscriptions(model: Model): Sub[IO, Msg] = + Sub.Batch { + model.bridge.subscribe { case msg => + Some(Msg.IndigoReceive(msg)) + } + } + + def updateIndigoReceive(msg: GloomhavenMsg, model: Model): (Model, Cmd[IO, Msg]) = + msg match { + case _ => + (model, Cmd.None) + // (model, cmd.map(Msg.IndigoSend(_))) + } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Model.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Model.scala new file mode 100644 index 00000000..d2e53a0b --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Model.scala @@ -0,0 +1,20 @@ +package vgb.ui + +import cats.effect.IO +import vgb.common.GloomhavenMsg +import tyrian.TyrianIndigoBridge + +/** Represents a model for the application + * + * @param bridge + * The bridge between Indigo and Tyrian + */ +final case class Model( + bridge: TyrianIndigoBridge[IO, GloomhavenMsg] +) + +object Model: + def apply(): Model = + Model( + TyrianIndigoBridge() + ) diff --git a/VirtualGloomhavenBoard/assets/browserconfig.xml b/VirtualGloomhavenBoard/Indigo/wwwroot/browserconfig.xml similarity index 91% rename from VirtualGloomhavenBoard/assets/browserconfig.xml rename to VirtualGloomhavenBoard/Indigo/wwwroot/browserconfig.xml index 417398a5..02e71754 100644 --- a/VirtualGloomhavenBoard/assets/browserconfig.xml +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/browserconfig.xml @@ -1,2 +1,2 @@ -#915d42 \ No newline at end of file +#915d42 diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.eot b/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.eot similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.eot rename to VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.eot diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.otf b/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.otf similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.otf rename to VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.otf diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.svg b/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.svg similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.svg rename to VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.svg diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.ttf b/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.ttf similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.ttf rename to VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.ttf diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.woff b/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.woff similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.woff rename to VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.woff diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.woff2 b/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.woff2 similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.woff2 rename to VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.woff2 diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-144x144.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-192x192.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-192x192.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-192x192.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-192x192.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-36x36.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-36x36.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-36x36.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-36x36.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-48x48.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-48x48.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-48x48.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-48x48.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-72x72.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-72x72.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-72x72.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-72x72.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-96x96.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-96x96.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-96x96.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-96x96.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/app.ico b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/app.ico similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/app.ico rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/app.ico diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-114x114.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-114x114.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-114x114.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-114x114.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-120x120.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-120x120.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-120x120.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-120x120.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-144x144.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-152x152.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-152x152.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-152x152.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-152x152.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-180x180.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-180x180.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-180x180.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-180x180.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-57x57.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-57x57.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-57x57.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-57x57.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-60x60.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-60x60.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-60x60.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-60x60.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-72x72.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-72x72.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-72x72.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-72x72.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-76x76.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-76x76.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-76x76.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-76x76.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-precomposed.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-precomposed.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-precomposed.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-precomposed.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/favicon-16x16.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-16x16.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/favicon-16x16.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-16x16.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/favicon-32x32.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-32x32.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/favicon-32x32.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-32x32.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/favicon-96x96.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-96x96.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/favicon-96x96.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-96x96.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/favicon.ico b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon.ico similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/favicon.ico rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon.ico diff --git a/VirtualGloomhavenBoard/assets/img/favicons/ms-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/ms-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-144x144.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/ms-icon-150x150.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-150x150.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/ms-icon-150x150.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-150x150.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/ms-icon-310x310.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-310x310.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/ms-icon-310x310.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-310x310.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/ms-icon-70x70.png b/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-70x70.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/ms-icon-70x70.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-70x70.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/index.html b/VirtualGloomhavenBoard/Indigo/wwwroot/index.html new file mode 100644 index 00000000..8729ee64 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/index.html @@ -0,0 +1,43 @@ + + + + + + + + Virtual Gloomhaven Board + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js b/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js new file mode 100644 index 00000000..6493ea8d --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js @@ -0,0 +1,247 @@ +//require('@microsoft/signalr') +import * as t from '../../out/vgb-ui/fastOpt.dest/out.js'; +t.TyrianApp.launch("main") +/* +const conn = new signalR + .HubConnectionBuilder() + .withUrl("/ws") + .withHubProtocol(new signalR.protocols.msgpack.MessagePackHubProtocol()) + .configureLogging(signalR.LogLevel.Information) + .withAutomaticReconnect([0, 3000, 5000, 10000, 15000, 30000]) + .build() + ; + +let lastGameState = null; +let roomCode = null; + +conn.onreconnected(() => app.ports.connected.send(null)); +conn.onreconnecting(() => app.ports.reconnecting.send(null)); +conn.onclose(() => app.ports.disconnected.send(null)); + +conn.on("RoomCreated", (newRoomCode) => { + roomCode = newRoomCode; + app.ports.receiveRoomCode.send(newRoomCode) +}); + +conn.on("InvalidRoomCode", () => + app.ports.invalidRoomCode.send(null) +); + +conn.on("ReceiveGameState", (state) => { + app.ports.receiveUpdate.send(state) +}); + +conn.on("PushGameState", () => { + if (lastGameState !== null && roomCode !== null) + conn + .invoke("SendGameState", roomCode, lastGameState) + .catch(err => console.error(err)) + ; +}); + +app.ports.saveData.subscribe((data) => { + lastGameState = data.gameState; + window.localStorage.setItem("state", JSON.stringify(data)) +}); + +app.ports.connect.subscribe(async () => { + if (conn.state === signalR.HubConnectionState.Disconnected) { + try { + await conn.start(); + app.ports.connected.send(null); + } catch (err) { + console.log(err); + app.ports.disconnected.send(null); + } + } +}); + +app.ports.createRoom.subscribe(seed => { + if (conn.state === signalR.HubConnectionState.Connected) + conn + .invoke("CreateRoom", seed) + .catch(err => console.error(err)) + ; +}); + +app.ports.joinRoom.subscribe((args) => { + const oldCode = args[0]; + const newCode = args[1]; + + if (oldCode !== null) + conn.invoke("LeaveRoom", oldCode).catch(err => console.error(err)); + + roomCode = newCode; + conn.invoke("JoinRoom", newCode).catch(err => console.error(err)); +}); + +app.ports.sendUpdate.subscribe((args) => { + lastGameState = args[1]; + conn.invoke("SendGameState", args[0], args[1]).catch(err => console.error(err)); +}); + +app.ports.toggleFullscreenPort.subscribe((enabled) => { + const elem = document.getElementById('content') + if (enabled && document.fullscreenEnabled && !document.fullscreenElement) { + elem.requestFullscreen(); + elem.onfullscreenchange = () => { + if (!document.fullscreenElement) + app.ports.exitFullscreen.send(null) + }; + } + else if (!enabled && document.fullscreenElement) + document.exitFullscreen(); +}); + +app.ports.getCellFromPoint.subscribe((args) => { + let elem = document.elementFromPoint(args[0], args[1]) + let i = 0 + + while (i++ != 100 && elem != null && elem.className.substring(0, 7) != 'hexagon') + elem = elem.parentElement + + if (elem == null || elem.className.substring(0, 7) != 'hexagon') + return; + + app.ports.onCellFromPoint.send([ + parseInt(elem.dataset.cellX), + parseInt(elem.dataset.cellY), + args[2] + ]) +}); + +app.ports.getContextPosition.subscribe((args) => { + let elem = document + .querySelector("[data-cell-x='" + args[0] + "'][data-cell-y='" + args[1] + "']") + ; + + let contextMenus = document.getElementsByClassName('context-menu'); + + if (elem == null || contextMenus == null || contextMenus.length == 0 || elem.className.substring(0, 7) != 'hexagon') + return; + + let contextMenu = contextMenus[0]; + let compare = elem; + let offsetX = elem.offsetLeft; + let offsetY = elem.offsetTop; + do { + compare = compare.offsetParent; + + offsetX += compare.offsetLeft; + offsetY += compare.offsetTop; + } while (!compare.offsetParent.classList.contains('board-wrapper')) + + offsetY += 25; + offsetX += parseInt(contextMenu.clientWidth / 4); + + // compare is now the row + let wrapper = compare.offsetParent; + + offsetX -= wrapper.scrollLeft; + offsetY -= wrapper.scrollTop; + + if (offsetX + contextMenu.clientWidth > wrapper.scrollWidth) + offsetX -= parseInt((contextMenu.clientWidth / 2) + parseInt(contextMenu.clientWidth / 4)) + + if (offsetY + contextMenu.clientHeight > wrapper.scrollHeight) + offsetY -= contextMenu.clientHeight + + app.ports.onContextPosition.send([offsetX, offsetY]); +}); + +var scrollCheck = null; +app.ports.scrollToFirtVisibleCell.subscribe(() => { + if (scrollCheck === null) + scrollCheck = setInterval(() => { + var board = document.getElementById("board"); + if (board === null || board === undefined) + return; + + var cells = board.getElementsByClassName('cell-wrapper'); + if (cells === null || cells === undefined) + return; + + var firstCell = null; + var cellX = 0; + var cellY = 0; + for (var i = cells.length - 1; i >= 0; i--) { + if (cells[i].classList.contains('passable')) { + var hex = cells[i].getElementsByClassName('hexagon')[0]; + var hexX = parseInt(hex.dataset.cellX); + var hexY = parseInt(hex.dataset.cellY); + + if (firstCell == null || hexY < cellY || (hexY === cellY && hexX < cellX)) { + firstCell = hex; + cellX = hexX; + cellY = hexY; + } + } + } + + if (firstCell !== null) { + var bounds = hex.getBoundingClientRect(); + var targetX = bounds.left - 225; + var targetY = bounds.top - 100; + + board.scrollBy(targetX, targetY); + + clearInterval(scrollCheck); + scrollCheck = null; + } + }, 100); +}); + +document.addEventListener('paste', (event) => { + app.ports.onPaste.send((event.clipboardData || window.clipboardData).getData('text')); + event.preventDefault(); +}) + +function generateOverrides() { + const scenarioId = getUrlParameter('scenario'); + const players = getUrlParameter('players'); + const roomCodeSeed = getUrlParameter('seed'); + + let o = { + initScenario: null, + initPlayers: null, + initRoomCodeSeed: null, + lockScenario: getUrlParameter('lockScenario') === '1', + lockPlayers: getUrlParameter('lockPlayers') === '1', + lockRoomCode: getUrlParameter('lockRoomCode') === '1' + }; + + if (scenarioId !== undefined) { + const id = parseInt(scenarioId); + if (!isNaN(id)) + o.initScenario = id; + } + + if (players != undefined) + o.initPlayers = players.replace(/\s+/g, "").split(','); + + if (roomCodeSeed !== undefined) { + const seed = parseInt(roomCodeSeed); + if (!isNaN(seed)) + o.initRoomCodeSeed = seed; + } + + if (document.referrer !== "") { + if (document.referrer.includes("gloomhaven-storyline.com")) { + o.campaignTracker = { + name: "Gloomhaven Storyline", + url: "https://gloomhaven-storyline.com/tracker/#/story/{scenarioId}" + } + } + } + + return o; +} + +function getUrlParameter(name) { + name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); + var regex = new RegExp('[\\?&]' + name + '=([^&#]*)'); + var results = regex.exec(location.search); + return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' ')); +}; + +TyrianApp.launch("main", generateOverrides());*/ diff --git a/VirtualGloomhavenBoard/assets/manifest.json b/VirtualGloomhavenBoard/Indigo/wwwroot/manifest.json similarity index 100% rename from VirtualGloomhavenBoard/assets/manifest.json rename to VirtualGloomhavenBoard/Indigo/wwwroot/manifest.json diff --git a/VirtualGloomhavenBoard/Indigo/yarn.lock b/VirtualGloomhavenBoard/Indigo/yarn.lock new file mode 100644 index 00000000..3b89d6b8 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/yarn.lock @@ -0,0 +1,2097 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" + integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== + dependencies: + "@babel/highlight" "^7.18.6" + +"@babel/helper-validator-identifier@^7.18.6": + version "7.19.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" + integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== + +"@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/helper-validator-identifier" "^7.18.6" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.0": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@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.3" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" + integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@lezer/common@^0.15.0", "@lezer/common@^0.15.7": + version "0.15.12" + resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.12.tgz#2f21aec551dd5fd7d24eb069f90f54d5bc6ee5e9" + integrity sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig== + +"@lezer/lr@^0.15.4": + version "0.15.8" + resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.8.tgz#1564a911e62b0a0f75ca63794a6aa8c5dc63db21" + integrity sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg== + dependencies: + "@lezer/common" "^0.15.0" + +"@lmdb/lmdb-darwin-arm64@2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz#bc66fa43286b5c082e8fee0eacc17995806b6fbe" + integrity sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A== + +"@lmdb/lmdb-darwin-x64@2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz#89d8390041bce6bab24a82a20392be22faf54ffc" + integrity sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA== + +"@lmdb/lmdb-linux-arm64@2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz#14fe4c96c2bb1285f93797f45915fa35ee047268" + integrity sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ== + +"@lmdb/lmdb-linux-arm@2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz#05bde4573ab10cf21827339fe687148f2590cfa1" + integrity sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw== + +"@lmdb/lmdb-linux-x64@2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz#d2f85afd857d2c33d2caa5b057944574edafcfee" + integrity sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q== + +"@lmdb/lmdb-win32-x64@2.5.2": + version "2.5.2" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz#28f643fbc0bec30b07fbe95b137879b6b4d1c9c5" + integrity sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA== + +"@microsoft/signalr-protocol-msgpack@^6.0.2": + version "6.0.16" + resolved "https://registry.yarnpkg.com/@microsoft/signalr-protocol-msgpack/-/signalr-protocol-msgpack-6.0.16.tgz#71ad16d1759079e2894d89d53764c48bed467165" + integrity sha512-cEbtkYZ9cmcdxsdYn2N5ZKX6GAgQClYHqe4p9Y7Gs1WyUXSpIXDWM7JLnMuFaoQJDw2Jhh/lizdTUvJUcMKrAQ== + dependencies: + "@microsoft/signalr" ">=6.0.16" + "@msgpack/msgpack" "^2.7.0" + +"@microsoft/signalr@>=6.0.16": + version "7.0.5" + resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-7.0.5.tgz#e7a984ac1f1b6a488170e9cb2f2f46a5d97d5f80" + integrity sha512-j84syCKlXkQAOQhyrzRmW7w/M2UXQ6OKcXXFIVNjmiiZbEGIvSvJDRAuyMFjArdQOXz+etJgd58H/prTbyTCrA== + dependencies: + abort-controller "^3.0.0" + eventsource "^2.0.2" + fetch-cookie "^2.0.3" + node-fetch "^2.6.7" + ws "^7.4.5" + +"@microsoft/signalr@^6.0.2": + version "6.0.16" + resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.16.tgz#d36498a9b16bf11c0e9213d77d24c0ad8ebffa47" + integrity sha512-wekzRtt2Ti38Ja0OQwLE0EKN0Zm7RI9VilrungwHe5Eej1IwnRYuhpauAqNtwwP3CY2j7uFT4XUk74E2vythTQ== + dependencies: + abort-controller "^3.0.0" + eventsource "^1.0.7" + fetch-cookie "^0.11.0" + node-fetch "^2.6.7" + ws "^7.4.5" + +"@mischnic/json-sourcemap@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507" + integrity sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA== + dependencies: + "@lezer/common" "^0.15.7" + "@lezer/lr" "^0.15.4" + json5 "^2.2.1" + +"@msgpack/msgpack@^2.7.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-2.8.0.tgz#4210deb771ee3912964f14a15ddfb5ff877e70b9" + integrity sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ== + +"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz#44d752c1a2dc113f15f781b7cc4f53a307e3fa38" + integrity sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ== + +"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz#f954f34355712212a8e06c465bc06c40852c6bb3" + integrity sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw== + +"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz#45c63037f045c2b15c44f80f0393fa24f9655367" + integrity sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg== + +"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz#35707efeafe6d22b3f373caf9e8775e8920d1399" + integrity sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA== + +"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz#091b1218b66c341f532611477ef89e83f25fae4f" + integrity sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA== + +"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407" + integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ== + +"@parcel/bundler-default@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.8.3.tgz#d64739dbc2dbd59d6629861bf77a8083aced5229" + integrity sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/graph" "2.8.3" + "@parcel/hash" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + nullthrows "^1.1.1" + +"@parcel/cache@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.8.3.tgz#169e130cf59913c0ed9fadce1a450e68f710e16f" + integrity sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ== + dependencies: + "@parcel/fs" "2.8.3" + "@parcel/logger" "2.8.3" + "@parcel/utils" "2.8.3" + lmdb "2.5.2" + +"@parcel/codeframe@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.8.3.tgz#84fb529ef70def7f5bc64f6c59b18d24826f5fcc" + integrity sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg== + dependencies: + chalk "^4.1.0" + +"@parcel/compressor-raw@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz#301753df8c6de967553149639e8a4179b88f0c95" + integrity sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg== + dependencies: + "@parcel/plugin" "2.8.3" + +"@parcel/config-default@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.8.3.tgz#9a43486e7c702e96c68052c37b79098d7240e35b" + integrity sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw== + dependencies: + "@parcel/bundler-default" "2.8.3" + "@parcel/compressor-raw" "2.8.3" + "@parcel/namer-default" "2.8.3" + "@parcel/optimizer-css" "2.8.3" + "@parcel/optimizer-htmlnano" "2.8.3" + "@parcel/optimizer-image" "2.8.3" + "@parcel/optimizer-svgo" "2.8.3" + "@parcel/optimizer-terser" "2.8.3" + "@parcel/packager-css" "2.8.3" + "@parcel/packager-html" "2.8.3" + "@parcel/packager-js" "2.8.3" + "@parcel/packager-raw" "2.8.3" + "@parcel/packager-svg" "2.8.3" + "@parcel/reporter-dev-server" "2.8.3" + "@parcel/resolver-default" "2.8.3" + "@parcel/runtime-browser-hmr" "2.8.3" + "@parcel/runtime-js" "2.8.3" + "@parcel/runtime-react-refresh" "2.8.3" + "@parcel/runtime-service-worker" "2.8.3" + "@parcel/transformer-babel" "2.8.3" + "@parcel/transformer-css" "2.8.3" + "@parcel/transformer-html" "2.8.3" + "@parcel/transformer-image" "2.8.3" + "@parcel/transformer-js" "2.8.3" + "@parcel/transformer-json" "2.8.3" + "@parcel/transformer-postcss" "2.8.3" + "@parcel/transformer-posthtml" "2.8.3" + "@parcel/transformer-raw" "2.8.3" + "@parcel/transformer-react-refresh-wrap" "2.8.3" + "@parcel/transformer-svg" "2.8.3" + +"@parcel/core@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.8.3.tgz#22a69f36095d53736ab10bf42697d9aa5f4e382b" + integrity sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ== + dependencies: + "@mischnic/json-sourcemap" "^0.1.0" + "@parcel/cache" "2.8.3" + "@parcel/diagnostic" "2.8.3" + "@parcel/events" "2.8.3" + "@parcel/fs" "2.8.3" + "@parcel/graph" "2.8.3" + "@parcel/hash" "2.8.3" + "@parcel/logger" "2.8.3" + "@parcel/package-manager" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/types" "2.8.3" + "@parcel/utils" "2.8.3" + "@parcel/workers" "2.8.3" + abortcontroller-polyfill "^1.1.9" + base-x "^3.0.8" + browserslist "^4.6.6" + clone "^2.1.1" + dotenv "^7.0.0" + dotenv-expand "^5.1.0" + json5 "^2.2.0" + msgpackr "^1.5.4" + nullthrows "^1.1.1" + semver "^5.7.1" + +"@parcel/diagnostic@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.8.3.tgz#d560276d5d2804b48beafa1feaf3fc6b2ac5e39d" + integrity sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ== + dependencies: + "@mischnic/json-sourcemap" "^0.1.0" + nullthrows "^1.1.1" + +"@parcel/events@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.8.3.tgz#205f8d874e6ecc2cbdb941bf8d54bae669e571af" + integrity sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w== + +"@parcel/fs-search@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.8.3.tgz#1c7d812c110b808758f44c56e61dfffdb09e9451" + integrity sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ== + dependencies: + detect-libc "^1.0.3" + +"@parcel/fs@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.8.3.tgz#80536afe877fc8a2bd26be5576b9ba27bb4c5754" + integrity sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ== + dependencies: + "@parcel/fs-search" "2.8.3" + "@parcel/types" "2.8.3" + "@parcel/utils" "2.8.3" + "@parcel/watcher" "^2.0.7" + "@parcel/workers" "2.8.3" + +"@parcel/graph@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.8.3.tgz#00ffe8ec032e74fee57199e54529f1da7322571d" + integrity sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg== + dependencies: + nullthrows "^1.1.1" + +"@parcel/hash@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.8.3.tgz#bc2499a27395169616cad2a99e19e69b9098f6e9" + integrity sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw== + dependencies: + detect-libc "^1.0.3" + xxhash-wasm "^0.4.2" + +"@parcel/logger@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.8.3.tgz#e14e4debafb3ca9e87c07c06780f9afc38b2712c" + integrity sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/events" "2.8.3" + +"@parcel/markdown-ansi@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz#1337d421bb1133ad178f386a8e1b746631bba4a1" + integrity sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ== + dependencies: + chalk "^4.1.0" + +"@parcel/namer-default@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.8.3.tgz#5304bee74beb4b9c1880781bdbe35be0656372f4" + integrity sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + nullthrows "^1.1.1" + +"@parcel/node-resolver-core@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz#581df074a27646400b3fed9da95297b616a7db8f" + integrity sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/utils" "2.8.3" + nullthrows "^1.1.1" + semver "^5.7.1" + +"@parcel/optimizer-css@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz#420a333f4b78f7ff15e69217dfed34421b1143ee" + integrity sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/utils" "2.8.3" + browserslist "^4.6.6" + lightningcss "^1.16.1" + nullthrows "^1.1.1" + +"@parcel/optimizer-htmlnano@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz#a71ab6f0f24160ef9f573266064438eff65e96d0" + integrity sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg== + dependencies: + "@parcel/plugin" "2.8.3" + htmlnano "^2.0.0" + nullthrows "^1.1.1" + posthtml "^0.16.5" + svgo "^2.4.0" + +"@parcel/optimizer-image@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz#ea49b4245b4f7d60b38c7585c6311fb21d341baa" + integrity sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + "@parcel/workers" "2.8.3" + detect-libc "^1.0.3" + +"@parcel/optimizer-svgo@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz#04da4efec6b623679539a84961bff6998034ba8a" + integrity sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + svgo "^2.4.0" + +"@parcel/optimizer-terser@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz#3a06d98d09386a1a0ae1be85376a8739bfba9618" + integrity sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/utils" "2.8.3" + nullthrows "^1.1.1" + terser "^5.2.0" + +"@parcel/package-manager@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.8.3.tgz#ddd0d62feae3cf0fb6cc0537791b3a16296ad458" + integrity sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/fs" "2.8.3" + "@parcel/logger" "2.8.3" + "@parcel/types" "2.8.3" + "@parcel/utils" "2.8.3" + "@parcel/workers" "2.8.3" + semver "^5.7.1" + +"@parcel/packager-css@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.8.3.tgz#0eff34268cb4f5dfb53c1bbca85f5567aeb1835a" + integrity sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/utils" "2.8.3" + nullthrows "^1.1.1" + +"@parcel/packager-html@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.8.3.tgz#f9263b891aa4dd46c6e2fa2b07025a482132fff1" + integrity sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/types" "2.8.3" + "@parcel/utils" "2.8.3" + nullthrows "^1.1.1" + posthtml "^0.16.5" + +"@parcel/packager-js@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.8.3.tgz#3ed11565915d73d12192b6901c75a6b820e4a83a" + integrity sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/hash" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/utils" "2.8.3" + globals "^13.2.0" + nullthrows "^1.1.1" + +"@parcel/packager-raw-url@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/packager-raw-url/-/packager-raw-url-2.8.3.tgz#5994dca47f37a395deb0fd5b574a9d4656617f47" + integrity sha512-v8k/x2pnR3DDiIJrPTUcBd+MjH9ocpac0dsdJ02yeyGIQTecqL6nuCtu6W4m75CC7vFjjh/aCK9TJsOHOFnCFQ== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + +"@parcel/packager-raw@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.8.3.tgz#bdec826df991e186cb58691cc45d12ad5c06676e" + integrity sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA== + dependencies: + "@parcel/plugin" "2.8.3" + +"@parcel/packager-svg@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.8.3.tgz#7233315296001c531cb55ca96b5f2ef672343630" + integrity sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/types" "2.8.3" + "@parcel/utils" "2.8.3" + posthtml "^0.16.4" + +"@parcel/plugin@2.8.3", "@parcel/plugin@^2.0.0-beta.1": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.8.3.tgz#7bb30a5775eaa6473c27f002a0a3ee7308d6d669" + integrity sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw== + dependencies: + "@parcel/types" "2.8.3" + +"@parcel/reporter-cli@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz#12a4743b51b8fe6837f53c20e01bbf1f7336e8e4" + integrity sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/types" "2.8.3" + "@parcel/utils" "2.8.3" + chalk "^4.1.0" + term-size "^2.2.1" + +"@parcel/reporter-dev-server@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz#a0daa5cc015642684cea561f4e0e7116bbffdc1c" + integrity sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + +"@parcel/resolver-default@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.8.3.tgz#5ae41e537ae4a793c1abb47f094482b9e2ac3535" + integrity sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A== + dependencies: + "@parcel/node-resolver-core" "2.8.3" + "@parcel/plugin" "2.8.3" + +"@parcel/runtime-browser-hmr@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz#1fa74e1fbd1030b0a920c58afa3a9eb7dc4bcd1e" + integrity sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + +"@parcel/runtime-js@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.8.3.tgz#0baa4c8fbf77eabce05d01ccc186614968ffc0cd" + integrity sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + nullthrows "^1.1.1" + +"@parcel/runtime-react-refresh@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz#381a942fb81e8f5ac6c7e0ee1b91dbf34763c3f8" + integrity sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + react-error-overlay "6.0.9" + react-refresh "^0.9.0" + +"@parcel/runtime-service-worker@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz#54d92da9ff1dfbd27db0e84164a22fa59e99b348" + integrity sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + nullthrows "^1.1.1" + +"@parcel/source-map@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.1.tgz#fb193b82dba6dd62cc7a76b326f57bb35000a782" + integrity sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew== + dependencies: + detect-libc "^1.0.3" + +"@parcel/transformer-babel@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz#286bc6cb9afe4c0259f0b28e0f2f47322a24b130" + integrity sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/utils" "2.8.3" + browserslist "^4.6.6" + json5 "^2.2.0" + nullthrows "^1.1.1" + semver "^5.7.0" + +"@parcel/transformer-css@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.8.3.tgz#d6c44100204e73841ad8e0f90472172ea8b9120c" + integrity sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/utils" "2.8.3" + browserslist "^4.6.6" + lightningcss "^1.16.1" + nullthrows "^1.1.1" + +"@parcel/transformer-html@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.8.3.tgz#5c68b28ee6b8c7a13b8aee87f7957ad3227bd83f" + integrity sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/hash" "2.8.3" + "@parcel/plugin" "2.8.3" + nullthrows "^1.1.1" + posthtml "^0.16.5" + posthtml-parser "^0.10.1" + posthtml-render "^3.0.0" + semver "^5.7.1" + srcset "4" + +"@parcel/transformer-image@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.8.3.tgz#73805b2bfc3c8919d7737544e5f8be39e3f303fe" + integrity sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + "@parcel/workers" "2.8.3" + nullthrows "^1.1.1" + +"@parcel/transformer-js@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.8.3.tgz#fe400df428394d1e7fe5afb6dea5c7c858e44f03" + integrity sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/utils" "2.8.3" + "@parcel/workers" "2.8.3" + "@swc/helpers" "^0.4.12" + browserslist "^4.6.6" + detect-libc "^1.0.3" + nullthrows "^1.1.1" + regenerator-runtime "^0.13.7" + semver "^5.7.1" + +"@parcel/transformer-json@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.8.3.tgz#25deb3a5138cc70a83269fc5d39d564609354d36" + integrity sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg== + dependencies: + "@parcel/plugin" "2.8.3" + json5 "^2.2.0" + +"@parcel/transformer-postcss@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz#df4fdc1c90893823445f2a8eb8e2bdd0349ccc58" + integrity sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/hash" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + clone "^2.1.1" + nullthrows "^1.1.1" + postcss-value-parser "^4.2.0" + semver "^5.7.1" + +"@parcel/transformer-posthtml@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz#7c3912a5a631cb26485f6464e0d6eeabb6f1e718" + integrity sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + nullthrows "^1.1.1" + posthtml "^0.16.5" + posthtml-parser "^0.10.1" + posthtml-render "^3.0.0" + semver "^5.7.1" + +"@parcel/transformer-raw@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz#3a22213fe18a5f83fd78889cb49f06e059cfead7" + integrity sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ== + dependencies: + "@parcel/plugin" "2.8.3" + +"@parcel/transformer-react-refresh-wrap@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz#8b0392638405dd470a886002229f7889d5464822" + integrity sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + react-refresh "^0.9.0" + +"@parcel/transformer-sass@^2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-sass/-/transformer-sass-2.8.3.tgz#d3a0388e77c1e6279b488ccd0abf612d3a0897ff" + integrity sha512-ak196rjvXdsBOGi5aTkBEKv6i4LKQgOkHuaKEjeT8g2a3CU6Z36J+j2GbZzsznfws/hH+CRTf8bAsbkxtKlkjQ== + dependencies: + "@parcel/plugin" "2.8.3" + "@parcel/source-map" "^2.1.1" + sass "^1.38.0" + +"@parcel/transformer-svg@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz#4df959cba4ebf45d7aaddd540f752e6e84df38b2" + integrity sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/hash" "2.8.3" + "@parcel/plugin" "2.8.3" + nullthrows "^1.1.1" + posthtml "^0.16.5" + posthtml-parser "^0.10.1" + posthtml-render "^3.0.0" + semver "^5.7.1" + +"@parcel/transformer-webmanifest@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/transformer-webmanifest/-/transformer-webmanifest-2.8.3.tgz#5858079bf5abaedcf42dc5e856248a596277dc71" + integrity sha512-v3NuQc1K1AMfD1+hvh/YYpxBEin52CvEX94MnjwYK6bDmJ35rNuttIs7T6DZxAOopRbGwoTchCShIbv15gTcvg== + dependencies: + "@mischnic/json-sourcemap" "^0.1.0" + "@parcel/diagnostic" "2.8.3" + "@parcel/plugin" "2.8.3" + "@parcel/utils" "2.8.3" + +"@parcel/types@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.8.3.tgz#3306bc5391b6913bd619914894b8cd84a24b30fa" + integrity sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw== + dependencies: + "@parcel/cache" "2.8.3" + "@parcel/diagnostic" "2.8.3" + "@parcel/fs" "2.8.3" + "@parcel/package-manager" "2.8.3" + "@parcel/source-map" "^2.1.1" + "@parcel/workers" "2.8.3" + utility-types "^3.10.0" + +"@parcel/utils@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.8.3.tgz#0d56c9e8e22c119590a5e044a0e01031965da40e" + integrity sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA== + dependencies: + "@parcel/codeframe" "2.8.3" + "@parcel/diagnostic" "2.8.3" + "@parcel/hash" "2.8.3" + "@parcel/logger" "2.8.3" + "@parcel/markdown-ansi" "2.8.3" + "@parcel/source-map" "^2.1.1" + chalk "^4.1.0" + +"@parcel/watcher@^2.0.7": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.1.0.tgz#5f32969362db4893922c526a842d8af7a8538545" + integrity sha512-8s8yYjd19pDSsBpbkOHnT6Z2+UJSuLQx61pCFM0s5wSRvKCEMDjd/cHY3/GI1szHIWbpXpsJdg3V6ISGGx9xDw== + dependencies: + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^3.2.1" + node-gyp-build "^4.3.0" + +"@parcel/workers@2.8.3": + version "2.8.3" + resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.8.3.tgz#255450ccf4db234082407e4ddda5fd575f08c235" + integrity sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg== + dependencies: + "@parcel/diagnostic" "2.8.3" + "@parcel/logger" "2.8.3" + "@parcel/types" "2.8.3" + "@parcel/utils" "2.8.3" + chrome-trace-event "^1.0.2" + nullthrows "^1.1.1" + +"@swc/helpers@^0.4.12": + version "0.4.14" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74" + integrity sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw== + dependencies: + tslib "^2.4.0" + +"@trysound/sax@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +abortcontroller-polyfill@^1.1.9: + version "1.7.5" + resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" + integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== + +acorn@^8.5.0: + version "8.8.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +base-x@^3.0.8: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +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" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserslist@^4.6.6: + version "4.21.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" + integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== + dependencies: + caniuse-lite "^1.0.30001449" + electron-to-chromium "^1.4.284" + node-releases "^2.0.8" + update-browserslist-db "^1.0.10" + +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-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-lite@^1.0.30001449: + version "1.0.30001481" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz#f58a717afe92f9e69d0e35ff64df596bfad93912" + integrity sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ== + +chalk@^2.0.0: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +"chokidar@>=3.0.0 <4.0.0": + 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" + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^7.0.0, commander@^7.2.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== + +cosmiconfig@^8.0.0: + version "8.1.3" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689" + integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw== + dependencies: + import-fresh "^3.2.1" + js-yaml "^4.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +crypto-browserify@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-select@^4.1.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" + integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== + dependencies: + boolbase "^1.0.0" + css-what "^6.0.1" + domhandler "^4.3.1" + domutils "^2.8.0" + nth-check "^2.0.1" + +css-tree@^1.1.2, css-tree@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" + integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== + +csso@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dom-serializer@^1.0.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" + integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.0" + entities "^2.0.0" + +domelementtype@^2.0.1, domelementtype@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" + integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== + dependencies: + domelementtype "^2.2.0" + +domutils@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== + dependencies: + dom-serializer "^1.0.1" + domelementtype "^2.2.0" + domhandler "^4.2.0" + +dotenv-expand@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" + integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== + +dotenv@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" + integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== + +electron-to-chromium@^1.4.284: + version "1.4.372" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.372.tgz#7888ac92ccb9556627c3a37eba3b89ee5ac345f8" + integrity sha512-MrlFq/j+TYHOjeWsWGYfzevc25HNeJdsF6qaLFrqBTRWZQtWkb1myq/Q2veLWezVaa5OcSZ99CFwTT4aF4Mung== + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +entities@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" + integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-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 sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eventsource@^1.0.7: + version "1.1.2" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.2.tgz#bc75ae1c60209e7cb1541231980460343eaea7c2" + integrity sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA== + +eventsource@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508" + integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +fetch-cookie@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.11.0.tgz#e046d2abadd0ded5804ce7e2cae06d4331c15407" + integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== + dependencies: + tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" + +fetch-cookie@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-2.1.0.tgz#6e127909912f9e527533b045aab555c06b33801b" + integrity sha512-39+cZRbWfbibmj22R2Jy6dmTbAWC+oqun1f1FzQaNurkPDUP4C38jpeZbiXCR88RKRVDp8UcDrbFXkNhN+NjYg== + dependencies: + set-cookie-parser "^2.4.8" + tough-cookie "^4.0.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +get-port@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" + integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +globals@^13.2.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +htmlnano@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.0.4.tgz#315108063ed0bb6a16ccb53ad1b601f02d3fe721" + integrity sha512-WGCkyGFwjKW1GeCBsPYacMvaMnZtFJ0zIRnC2NCddkA+IOEhTqskXrS7lep+3yYZw/nQ3dW1UAX4yA/GJyR8BA== + dependencies: + cosmiconfig "^8.0.0" + posthtml "^0.16.5" + timsort "^0.3.0" + +htmlparser2@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5" + integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog== + dependencies: + domelementtype "^2.0.1" + domhandler "^4.2.2" + domutils "^2.8.0" + entities "^3.0.1" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +immutable@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be" + integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +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" + +is-json@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff" + integrity sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^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" + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json5@^2.2.0, json5@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +lightningcss-darwin-arm64@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.20.0.tgz#0416a0cb840944ea4aee972df02491c0168a784c" + integrity sha512-aYEohJTlzwB8URJaNiS57tMbjyLub0mYvxlxKQk8SZv+irXx6MoBWpDNQKKTS9gg1pGf/eAwjpa3BLAoCBsh1A== + +lightningcss-darwin-x64@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.20.0.tgz#4caa2b38fe223eabb32ebc3e1268a6b09e6b8d06" + integrity sha512-cmMgY8FFWVaGgtift7eKKkHMqlz9O09/yTdlCXEDOeDP9yeo6vHOBTRP7ojb368kjw8Ew3l0L2uT1Gtx56eNkg== + +lightningcss-linux-arm-gnueabihf@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.20.0.tgz#3e999a07aa77c10a06c9dda9b507c7a737f8521f" + integrity sha512-/m+NDO1O6JCv7R9F0XWlXcintQHx4MPNU+kt8jZJO07LLdGwCfvjN31GVcwVPlStnnx/cU8uTTmax6g/Qu/whg== + +lightningcss-linux-arm64-gnu@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.20.0.tgz#8b7786936ea462f744a85038fb033cc56049b677" + integrity sha512-gtXoa6v0HvMRLbev6Hsef0+Q5He7NslB+Rs7G49Y5LUSdJeGIATEN+j8JzHC0DnxCsOGbEgGRmvtJzzYDkkluw== + +lightningcss-linux-arm64-musl@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.20.0.tgz#8d812309c4e70398cee79fcdc452548ca521a6eb" + integrity sha512-Po7XpucM1kZnkiyd2BNwTExSDcZ8jm8uB9u+Sq44qjpkf5f75jreQwn3DQm9I1t5C6tB9HGt30HExMju9umJBQ== + +lightningcss-linux-x64-gnu@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.20.0.tgz#7652fbb26e50a5fa21b763aaebdb4bc657540c7e" + integrity sha512-8yR/fGNn/P0I+Lc3PK+VWPET/zdSpBfHFIG0DJ38TywMbItVKvnFvoTBwnIm4LqBz7g2G2dDexnNP95za2Ll8g== + +lightningcss-linux-x64-musl@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.20.0.tgz#aa21957fc51c363b4436e973911d01af4bed3c35" + integrity sha512-EmpJ+VkPZ8RACiB4m+l8TmapmE1W2UvJKDHE+ML/3Ihr9tRKUs3CibfnQTFZC8aSsrxgXagDAN+PgCDDhIyriA== + +lightningcss-win32-x64-msvc@1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.20.0.tgz#dcec3f7e03deda94504c93a9a03aec0484a5d5eb" + integrity sha512-BRdPvbq7Cc1qxAzp2emqWJHrqsEkf4ggxS29VOnxT7jhkdHKU+a26OVMjvm/OL0NH0ToNOZNAPvHMSexiEgBeA== + +lightningcss@^1.16.1: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.20.0.tgz#efa36a52feae9b0c8537c8e650a7819f549a4a23" + integrity sha512-4bj8aP+Vi+or8Gwq/hknmicr4PmA8D9uL/3qY0N0daX5vYBMYERGI6Y93nzoeRgQMULq+gtrN/FvJYtH0xNN8g== + dependencies: + detect-libc "^1.0.3" + optionalDependencies: + lightningcss-darwin-arm64 "1.20.0" + lightningcss-darwin-x64 "1.20.0" + lightningcss-linux-arm-gnueabihf "1.20.0" + lightningcss-linux-arm64-gnu "1.20.0" + lightningcss-linux-arm64-musl "1.20.0" + lightningcss-linux-x64-gnu "1.20.0" + lightningcss-linux-x64-musl "1.20.0" + lightningcss-win32-x64-msvc "1.20.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lmdb@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.5.2.tgz#37e28a9fb43405f4dc48c44cec0e13a14c4a6ff1" + integrity sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA== + dependencies: + msgpackr "^1.5.4" + node-addon-api "^4.3.0" + node-gyp-build-optional-packages "5.0.3" + ordered-binary "^1.2.4" + weak-lru-cache "^1.2.2" + optionalDependencies: + "@lmdb/lmdb-darwin-arm64" "2.5.2" + "@lmdb/lmdb-darwin-x64" "2.5.2" + "@lmdb/lmdb-linux-arm" "2.5.2" + "@lmdb/lmdb-linux-arm64" "2.5.2" + "@lmdb/lmdb-linux-x64" "2.5.2" + "@lmdb/lmdb-win32-x64" "2.5.2" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +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" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +msgpackr-extract@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz#e05ec1bb4453ddf020551bcd5daaf0092a2c279d" + integrity sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A== + dependencies: + node-gyp-build-optional-packages "5.0.7" + optionalDependencies: + "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.2" + "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.2" + "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.2" + "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.2" + "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" + "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" + +msgpackr@^1.5.4: + version "1.8.5" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.5.tgz#8cadfb935357680648f33699d0e833c9179dbfeb" + integrity sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg== + optionalDependencies: + msgpackr-extract "^3.0.1" + +node-addon-api@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-addon-api@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" + integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== + +node-fetch@^2.6.7: + version "2.6.9" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build-optional-packages@5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" + integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== + +node-gyp-build-optional-packages@5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3" + integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w== + +node-gyp-build@^4.3.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +node-releases@^2.0.8: + version "2.0.10" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" + integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +nullthrows@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" + integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== + +ordered-binary@^1.2.4: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.4.0.tgz#6bb53d44925f3b8afc33d1eed0fa15693b211389" + integrity sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ== + +parcel-reporter-static-files-copy@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/parcel-reporter-static-files-copy/-/parcel-reporter-static-files-copy-1.5.0.tgz#8ca7d7e4d1f0f52c30853117403696decf64da24" + integrity sha512-dsY3MQkbYSgEqS0/22vtD2mZtel8UC0ItH0ok8LmgFeCMTsdhyOtJgvt945ODIzu9lYc/sCIzksM8C77uSE3Fg== + dependencies: + "@parcel/plugin" "^2.0.0-beta.1" + +parcel@^2.8.3: + version "2.8.3" + resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.8.3.tgz#1ff71d7317274fd367379bc7310a52c6b75d30c2" + integrity sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA== + dependencies: + "@parcel/config-default" "2.8.3" + "@parcel/core" "2.8.3" + "@parcel/diagnostic" "2.8.3" + "@parcel/events" "2.8.3" + "@parcel/fs" "2.8.3" + "@parcel/logger" "2.8.3" + "@parcel/package-manager" "2.8.3" + "@parcel/reporter-cli" "2.8.3" + "@parcel/reporter-dev-server" "2.8.3" + "@parcel/utils" "2.8.3" + chalk "^4.1.0" + commander "^7.0.0" + get-port "^4.2.0" + v8-compile-cache "^2.0.0" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^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" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +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.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +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== + +posthtml-parser@^0.10.1: + version "0.10.2" + resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.2.tgz#df364d7b179f2a6bf0466b56be7b98fd4e97c573" + integrity sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg== + dependencies: + htmlparser2 "^7.1.1" + +posthtml-parser@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.11.0.tgz#25d1c7bf811ea83559bc4c21c189a29747a24b7a" + integrity sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw== + dependencies: + htmlparser2 "^7.1.1" + +posthtml-render@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205" + integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA== + dependencies: + is-json "^2.0.1" + +posthtml@^0.16.4, posthtml@^0.16.5: + version "0.16.6" + resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.6.tgz#e2fc407f67a64d2fa3567afe770409ffdadafe59" + integrity sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ== + dependencies: + posthtml-parser "^0.11.0" + posthtml-render "^3.0.0" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +react-error-overlay@6.0.9: + version "6.0.9" + resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" + integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== + +react-refresh@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" + integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== + +readable-stream@^3.5.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +regenerator-runtime@^0.13.7: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass@^1.38.0: + version "1.62.1" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.62.1.tgz#caa8d6bf098935bc92fc73fa169fb3790cacd029" + integrity sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + +semver@^5.7.0, semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +set-cookie-parser@^2.4.8: + version "2.6.0" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51" + integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +"source-map-js@>=0.6.2 <2.0.0": + 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.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.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +srcset@4: + version "4.0.0" + resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4" + integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw== + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +svgo@^2.4.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== + dependencies: + "@trysound/sax" "0.2.0" + commander "^7.2.0" + css-select "^4.1.3" + css-tree "^1.1.3" + csso "^4.2.0" + picocolors "^1.0.0" + stable "^0.1.8" + +term-size@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== + +terser@^5.2.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.1.tgz#948f10830454761e2eeedc6debe45c532c83fd69" + integrity sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw== + dependencies: + "@jridgewell/source-map" "^0.3.2" + acorn "^8.5.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" + integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +tslib@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +update-browserslist-db@^1.0.10: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utility-types@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" + integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== + +v8-compile-cache@^2.0.0: + 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== + +weak-lru-cache@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz#fdbb6741f36bae9540d12f480ce8254060dccd19" + integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +ws@^7.4.5: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + +xxhash-wasm@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79" + integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA== From 6a1479c7ef65e0fac907ee16def6bac72a3355b3 Mon Sep 17 00:00:00 2001 From: David North Date: Thu, 4 May 2023 08:36:06 +0100 Subject: [PATCH 27/60] Adds a map tile (a1a) with move icon No event yet for moving a tile, but the position is all correct --- VirtualGloomhavenBoard/Indigo/.parcelrc | 9 + VirtualGloomhavenBoard/Indigo/package.json | 4 +- .../Indigo/vgb-game/src/vgb/game/Main.scala | 26 +- .../src/vgb/game/models/BaseGame.scala | 4 + .../src/vgb/game/models/Expansion.scala | 12 + .../vgb-game/src/vgb/game/models/Room.scala | 17 + .../src/vgb/game/models/RoomType.scala | 53 + .../game/models/components/HexComponent.scala | 27 +- .../models/components/RoomComponent.scala | 24 + .../components/sceneModels/CreatorModel.scala | 6 + .../sceneModels/CreatorViewModel.scala | 3 + .../src/vgb/game/scenes/CreatorScene.scala | 51 +- .../Indigo/wwwroot/index.html | 30 +- .../Indigo/wwwroot/manifest.json | 46 - .../wwwroot/{ => static}/browserconfig.xml | 0 .../fonts/PirataOne-Gloomhaven.eot | Bin .../fonts/PirataOne-Gloomhaven.otf | Bin .../fonts/PirataOne-Gloomhaven.svg | 0 .../fonts/PirataOne-Gloomhaven.ttf | Bin .../fonts/PirataOne-Gloomhaven.woff | Bin .../fonts/PirataOne-Gloomhaven.woff2 | Bin .../img/favicons/android-icon-144x144.png | Bin .../img/favicons/android-icon-192x192.png | Bin .../img/favicons/android-icon-36x36.png | Bin .../img/favicons/android-icon-48x48.png | Bin .../img/favicons/android-icon-72x72.png | Bin .../img/favicons/android-icon-96x96.png | Bin .../wwwroot/{ => static}/img/favicons/app.ico | Bin .../img/favicons/apple-icon-114x114.png | Bin .../img/favicons/apple-icon-120x120.png | Bin .../img/favicons/apple-icon-144x144.png | Bin .../img/favicons/apple-icon-152x152.png | Bin .../img/favicons/apple-icon-180x180.png | Bin .../img/favicons/apple-icon-57x57.png | Bin .../img/favicons/apple-icon-60x60.png | Bin .../img/favicons/apple-icon-72x72.png | Bin .../img/favicons/apple-icon-76x76.png | Bin .../img/favicons/apple-icon-precomposed.png | Bin .../{ => static}/img/favicons/apple-icon.png | Bin .../img/favicons/favicon-16x16.png | Bin .../img/favicons/favicon-32x32.png | Bin .../img/favicons/favicon-96x96.png | Bin .../{ => static}/img/favicons/favicon.ico | Bin .../img/favicons/ms-icon-144x144.png | Bin .../img/favicons/ms-icon-150x150.png | Bin .../img/favicons/ms-icon-310x310.png | Bin .../img/favicons/ms-icon-70x70.png | Bin .../static/img/map-tiles/gloomhaven/a1a.png | Bin 0 -> 144335 bytes .../Indigo/wwwroot/static/img/move-icon.webp | Bin 0 -> 642 bytes .../Indigo/wwwroot/static/manifest.json | 46 + VirtualGloomhavenBoard/Indigo/yarn.lock | 2097 ----------------- 51 files changed, 253 insertions(+), 2202 deletions(-) create mode 100644 VirtualGloomhavenBoard/Indigo/.parcelrc create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BaseGame.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Expansion.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/RoomType.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/sceneModels/CreatorModel.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/sceneModels/CreatorViewModel.scala delete mode 100644 VirtualGloomhavenBoard/Indigo/wwwroot/manifest.json rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/browserconfig.xml (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/fonts/PirataOne-Gloomhaven.eot (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/fonts/PirataOne-Gloomhaven.otf (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/fonts/PirataOne-Gloomhaven.svg (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/fonts/PirataOne-Gloomhaven.ttf (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/fonts/PirataOne-Gloomhaven.woff (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/fonts/PirataOne-Gloomhaven.woff2 (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/android-icon-144x144.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/android-icon-192x192.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/android-icon-36x36.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/android-icon-48x48.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/android-icon-72x72.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/android-icon-96x96.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/app.ico (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-114x114.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-120x120.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-144x144.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-152x152.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-180x180.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-57x57.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-60x60.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-72x72.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-76x76.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon-precomposed.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/apple-icon.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/favicon-16x16.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/favicon-32x32.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/favicon-96x96.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/favicon.ico (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/ms-icon-144x144.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/ms-icon-150x150.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/ms-icon-310x310.png (100%) rename VirtualGloomhavenBoard/Indigo/wwwroot/{ => static}/img/favicons/ms-icon-70x70.png (100%) create mode 100644 VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1a.png create mode 100644 VirtualGloomhavenBoard/Indigo/wwwroot/static/img/move-icon.webp create mode 100644 VirtualGloomhavenBoard/Indigo/wwwroot/static/manifest.json delete mode 100644 VirtualGloomhavenBoard/Indigo/yarn.lock diff --git a/VirtualGloomhavenBoard/Indigo/.parcelrc b/VirtualGloomhavenBoard/Indigo/.parcelrc new file mode 100644 index 00000000..86a136fa --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/.parcelrc @@ -0,0 +1,9 @@ +{ + "extends": [ + "@parcel/config-default" + ], + "reporters": [ + "...", + "parcel-reporter-static-files-copy" + ] +} diff --git a/VirtualGloomhavenBoard/Indigo/package.json b/VirtualGloomhavenBoard/Indigo/package.json index 7c6a051d..aba723f4 100644 --- a/VirtualGloomhavenBoard/Indigo/package.json +++ b/VirtualGloomhavenBoard/Indigo/package.json @@ -8,9 +8,7 @@ "@microsoft/signalr-protocol-msgpack": "^6.0.2" }, "devDependencies": { - "@parcel/packager-raw-url": "2.8.3", "@parcel/transformer-sass": "^2.8.3", - "@parcel/transformer-webmanifest": "2.8.3", "buffer": "^5.7.1", "crypto-browserify": "^3.12.0", "events": "^3.3.0", @@ -20,7 +18,7 @@ "stream-browserify": "^3.0.0" }, "staticFiles": { - "staticPath": "wwwroot/", + "staticPath": "wwwroot/static", "watcherGlob": "**" }, "alias": { diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala index ebfd3394..f5c1f6e8 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala @@ -8,7 +8,7 @@ import vgb.common.* import vgb.game.scenes.* import vgb.game.models.GameModel import vgb.game.models.GameViewModel -import vgb.game.models.components.HexComponent +import indigo.shared.assets.AssetType final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) extends IndigoGame[Size, Size, GameModel, GameViewModel] { @@ -16,7 +16,7 @@ final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) val magnification = 1 def initialScene(bootData: Size): Option[SceneName] = - None + Some(SceneName("creator-scene")) def scenes(bootData: Size): NonEmptyList[Scene[Size, GameModel, GameViewModel]] = NonEmptyList(CreatorScene(tyrianSubSystem)) @@ -43,6 +43,10 @@ final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) gameViewport.size / magnification ) .withSubSystems(tyrianSubSystem) + .withAssets( + AssetType.Image(AssetName("a1a"), AssetPath("img/map-tiles/gloomhaven/a1a.png")), + AssetType.Image(AssetName("move-icon"), AssetPath("img/move-icon.webp")) + ) ) def setup( @@ -76,26 +80,12 @@ final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) model: GameModel, viewModel: GameViewModel ): GlobalEvent => Outcome[GameViewModel] = - case MouseEvent.Move(p) => - IndigoLogger.consoleLog(HexComponent.screenPosToOddRow(p).toString) - Outcome(viewModel) - case _ => Outcome(viewModel) + _ => Outcome(viewModel) def present( context: FrameContext[Size], model: GameModel, viewModel: GameViewModel ): Outcome[SceneUpdateFragment] = - Outcome( - SceneUpdateFragment( - Batch.fromArray( - (0 until 10).toArray - .map(x => - (0 until 10).toArray - .map(y => HexComponent.render(Point(x, y))) - ) - .flatten - ) - ) - ) + Outcome(SceneUpdateFragment.empty) } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BaseGame.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BaseGame.scala new file mode 100644 index 00000000..c2810d83 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BaseGame.scala @@ -0,0 +1,4 @@ +package vgb.game.models + +enum BaseGame: + case Gloomhaven, Frosthaven diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Expansion.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Expansion.scala new file mode 100644 index 00000000..0ad3a27c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Expansion.scala @@ -0,0 +1,12 @@ +package vgb.game.models + +enum Expansion(base: BaseGame): + override def toString(): String = + this match { + case None(base) => base.toString() + case Solo(base) => base.toString() + " Solo Scenarios" + case ForgottenCircles => base.toString() + " + FC" + } + case None(base: BaseGame) extends Expansion(base) + case Solo(base: BaseGame) extends Expansion(base) + case ForgottenCircles extends Expansion(BaseGame.Gloomhaven) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala new file mode 100644 index 00000000..55d0340f --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala @@ -0,0 +1,17 @@ +package vgb.game.models + +import indigo.* + +final case class Room(roomType: RoomType, origin: Point, numRotations: Byte) { + private val maxPoint = roomType.cells.foldLeft(Point.zero)((max, p) => max.max(p)) + private val minPoint = roomType.cells.foldLeft(maxPoint)((min, p) => min.min(p)) + lazy val rotationPoint = { + val midPoint = (maxPoint - minPoint).abs; + + Point((midPoint.x * 0.5).toInt, (midPoint.y * 0.5).toInt) + } + + def toWorldPos(localPos: Point) = + // Later we need to rotate this about the origin, then move it + localPos + origin +} diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/RoomType.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/RoomType.scala new file mode 100644 index 00000000..90457c1a --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/RoomType.scala @@ -0,0 +1,53 @@ +package vgb.game.models + +import indigo.* + +enum RoomType(val baseGame: BaseGame, val mapRef: String, val offset: Point, val cells: Batch[Point], val size: Size): + case RoomA1A + extends RoomType( + BaseGame.Gloomhaven, + "a1a", + Point(-13, -34), + Batch( + Point(0, 0), + Point(1, 0), + Point(2, 0), + Point(3, 0), + Point(0, 1), + Point(1, 1), + Point(2, 1), + Point(3, 1), + Point(4, 1) + ), + Size(432, 244) + ) + +/* +{ + tileset: "gloomhaven", + mapRef: "a1a", + offset: { + x: -16, + y: -34 + }, + cells: [ + { x: 0, y: 0 }, + + { x: 1, y: 0 }, + + { x: 2, y: 0 }, + + { x: 3, y: 0 }, + + { x: 0, y: 1 }, + + { x: 1, y: 1 }, + + { x: 2, y: 1 }, + + { x: 3, y: 1 }, + + { x: 4, y: 1 } + ] +} + */ diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala index a91479d4..575d3d24 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala @@ -5,18 +5,19 @@ import indigoextras.geometry.Vertex import indigo.shared.scenegraph.Shape.Line import indigo.shared.scenegraph.Shape.Polygon import indigo.shared.scenegraph.Shape.Circle +import indigo.shared.datatypes.Fill.Color object HexComponent: + val height = 90 private val sqrtThree = Math.sqrt(3) private val baseQ = sqrtThree / 3 private val oneOver3 = 1.0 / 3 private val twoOver3 = 2.0 / 3 private val threeOver2 = 3.0 / 2 - private val size = 90 - private val halfSize = size * 0.5 - private val quarterSize = size * 0.25 - private val rectWidth = sqrtThree * halfSize - private val halfWidth = rectWidth * 0.5 + private val halfSize = height * 0.5 + private val quarterSize = height * 0.25 + val width = sqrtThree * halfSize + private val halfWidth = width * 0.5 private val polygon = Polygon( Batch( Point(0, -Math.floor(halfSize).toInt), // Top tip @@ -26,22 +27,22 @@ object HexComponent: Point(-Math.ceil(halfWidth).toInt, Math.ceil(quarterSize).toInt), // Left-bottom corner of rectangle, Point(-Math.ceil(halfWidth).toInt, -Math.floor(quarterSize).toInt) // Left-top corner of rectangle ), - Fill.Color(RGBA.Green), + Fill.Color(RGBA.None), Stroke.Black ) - def render(position: Point): Group = + def render(position: Point, fill: RGBA = RGBA(0, 0, 0, 0)): Group = Group( polygon + .withFill(Fill.Color(fill)) // 0,0 position is the top left .moveTo(oddRowToScreenPos(position)) // For screen position to co-ordinates to work correctly, 0,0 needs to be centre - .moveBy((polygon.size.width * -0.5).toInt, (polygon.size.height * -0.5).toInt), - Circle(oddRowToScreenPos(position), 2, Fill.Color(RGBA.Red)) + .moveBy((polygon.size.width * -0.5).toInt, (polygon.size.height * -0.5).toInt) ) def screenPosToCube(pos: Point) = { - val q = (baseQ * pos.x.toDouble - (oneOver3 * pos.y.toDouble)) / halfSize.toDouble + val q = (baseQ * pos.x.toDouble + (oneOver3 * pos.y.toDouble)) / halfSize.toDouble val r = (twoOver3 * pos.y.toDouble) / halfSize.toDouble cubeRound(axialToCube(Vector2(q, r))) } @@ -51,7 +52,7 @@ object HexComponent: def axialToScreenPos(pos: Vector2) = Point( - (halfSize * (sqrtThree * pos.x + (sqrtThree * 0.5) * pos.y)).toInt, + (halfSize * (sqrtThree * pos.x - (sqrtThree * 0.5) * pos.y)).toInt, (halfSize * threeOver2 * pos.y).toInt ) @@ -60,12 +61,12 @@ object HexComponent: def oddRowToAxial(pos: Point) = Vector2( - pos.x - (pos.y - (pos.y.toInt & 1)) * 0.5, + pos.x + (pos.y - (pos.y.toInt & 1)) * 0.5, pos.y ) def cubeToOddRow(pos: Vector3) = - Vector2(pos.x + (pos.y - (pos.y.toInt & 1)) * 0.5, pos.y) + Vector2(pos.x - (pos.y - (pos.y.toInt & 1)) * 0.5, pos.y) def axialToCube(pos: Vector2) = Vector3(pos.x, pos.y, -pos.x - pos.y) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala new file mode 100644 index 00000000..50d1789f --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala @@ -0,0 +1,24 @@ +package vgb.game.models.components + +import indigo.* +import vgb.game.models.Room + +object RoomComponent: + def render(room: Room, moveable: Boolean) = + val origin = + HexComponent.oddRowToScreenPos(room.origin) + + Point(-HexComponent.width.toInt, -(HexComponent.height * 0.5).toInt) + + room.roomType.offset + Layer( + Batch( + Graphic(room.roomType.size, Material.Bitmap(AssetName(room.roomType.mapRef))) + .moveTo(origin) + ) ++ + (if moveable then + Batch( + Graphic(Size(45, 45), Material.Bitmap(AssetName("move-icon"))) + .moveTo(origin) + .moveBy(Point(16, -28)) + ) + else Batch.empty) + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/sceneModels/CreatorModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/sceneModels/CreatorModel.scala new file mode 100644 index 00000000..07776012 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/sceneModels/CreatorModel.scala @@ -0,0 +1,6 @@ +package vgb.game.models.components.sceneModels + +import indigo.* +import vgb.game.models.Room + +final case class CreatorModel(rooms: Batch[Room]) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/sceneModels/CreatorViewModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/sceneModels/CreatorViewModel.scala new file mode 100644 index 00000000..68047ec9 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/sceneModels/CreatorViewModel.scala @@ -0,0 +1,3 @@ +package vgb.game.models.components.sceneModels + +final case class CreatorViewModel() diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala index 8fc5e3dd..0d305eed 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -7,6 +7,13 @@ import tyrian.TyrianSubSystem import vgb.common.* import vgb.game.models.GameModel import vgb.game.models.GameViewModel +import indigo.shared.datatypes.RGBA +import vgb.game.models.components.HexComponent +import vgb.game.models.components.sceneModels.CreatorModel +import vgb.game.models.components.sceneModels.CreatorViewModel +import vgb.game.models.Room +import vgb.game.models.RoomType +import vgb.game.models.components.RoomComponent /** Placeholder scene for the space station * @@ -15,21 +22,26 @@ import vgb.game.models.GameViewModel final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) extends Scene[Size, GameModel, GameViewModel]: - type SceneModel = GameModel - type SceneViewModel = GameViewModel + type SceneModel = CreatorModel + type SceneViewModel = CreatorViewModel val name: SceneName = SceneName("creator-scene") - val modelLens: Lens[GameModel, SceneModel] = + val modelLens: Lens[GameModel, CreatorModel] = Lens( - (gameModel: GameModel) => gameModel, - (gameModel: GameModel, model: SceneModel) => model + (gameModel: GameModel) => + CreatorModel( + Batch( + Room(RoomType.RoomA1A, Point(2, 1), 0) + ) + ), + (gameModel: GameModel, model: CreatorModel) => gameModel ) - val viewModelLens: Lens[GameViewModel, SceneViewModel] = + val viewModelLens: Lens[GameViewModel, CreatorViewModel] = Lens( - (gameViewModel: GameViewModel) => gameViewModel, - (gameViewModel: GameViewModel, viewModel: SceneViewModel) => viewModel + (gameViewModel: GameViewModel) => CreatorViewModel(), + (gameViewModel: GameViewModel, viewModel: CreatorViewModel) => gameViewModel ) val eventFilters: EventFilters = @@ -49,8 +61,13 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg context: SceneContext[Size], model: SceneModel, viewModel: SceneViewModel - ): GlobalEvent => Outcome[SceneViewModel] = { case _ => - Outcome(viewModel) + ): GlobalEvent => Outcome[SceneViewModel] = { + + case MouseEvent.Move(p) => + IndigoLogger.consoleLog(HexComponent.screenPosToOddRow(p + Point(-150, -150)).toString) + Outcome(viewModel) + case _ => + Outcome(viewModel) } def present( @@ -60,4 +77,18 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg ): Outcome[SceneUpdateFragment] = Outcome( SceneUpdateFragment.empty + .addLayers(model.rooms.map(r => RoomComponent.render(r, true))) + .addLayer( + Layer( + Batch.fromArray( + (0 until 10).toArray + .map(x => + (0 until 10).toArray + .map(y => HexComponent.render(Point(x, y))) + ) + .flatten + ) + ) + ) + .withCamera(Camera.Fixed(Point(-150, -150))) ) diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/index.html b/VirtualGloomhavenBoard/Indigo/wwwroot/index.html index 8729ee64..8bfebc41 100644 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/index.html +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/index.html @@ -16,22 +16,22 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/manifest.json b/VirtualGloomhavenBoard/Indigo/wwwroot/manifest.json deleted file mode 100644 index 96980a88..00000000 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/manifest.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "Virtual Gloomhaven Board", - "short_name": "Virtual Gloomhaven Board", - "start_url": ".", - "display": "standalone", - "background_color": "#915d42", - "description": "An interactive board to allow players to remotely play Gloomhaven together.", - "icons": [ - { - "src": "\/img\/favicons\/android-icon-36x36.png", - "sizes": "36x36", - "type": "image\/png", - "density": "0.75" - }, - { - "src": "\/img\/favicons\/android-icon-48x48.png", - "sizes": "48x48", - "type": "image\/png", - "density": "1.0" - }, - { - "src": "\/img\/favicons\/android-icon-72x72.png", - "sizes": "72x72", - "type": "image\/png", - "density": "1.5" - }, - { - "src": "\/img\/favicons\/android-icon-96x96.png", - "sizes": "96x96", - "type": "image\/png", - "density": "2.0" - }, - { - "src": "\/img\/favicons\/android-icon-144x144.png", - "sizes": "144x144", - "type": "image\/png", - "density": "3.0" - }, - { - "src": "\/img\/favicons\/android-icon-192x192.png", - "sizes": "192x192", - "type": "image\/png", - "density": "4.0" - } - ] -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/browserconfig.xml b/VirtualGloomhavenBoard/Indigo/wwwroot/static/browserconfig.xml similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/browserconfig.xml rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/browserconfig.xml diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.eot b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.eot similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.eot rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.eot diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.otf b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.otf similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.otf rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.otf diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.svg b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.svg similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.svg rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.svg diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.ttf b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.ttf similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.ttf rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.ttf diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.woff b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.woff similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.woff rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.woff diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.woff2 b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.woff2 similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/fonts/PirataOne-Gloomhaven.woff2 rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.woff2 diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-144x144.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-192x192.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-192x192.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-192x192.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-192x192.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-36x36.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-36x36.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-36x36.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-36x36.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-48x48.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-48x48.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-48x48.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-48x48.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-72x72.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-72x72.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-72x72.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-72x72.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-96x96.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-96x96.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/android-icon-96x96.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-96x96.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/app.ico b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/app.ico similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/app.ico rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/app.ico diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-114x114.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-114x114.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-114x114.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-114x114.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-120x120.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-120x120.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-120x120.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-120x120.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-144x144.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-152x152.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-152x152.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-152x152.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-152x152.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-180x180.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-180x180.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-180x180.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-180x180.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-57x57.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-57x57.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-57x57.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-57x57.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-60x60.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-60x60.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-60x60.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-60x60.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-72x72.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-72x72.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-72x72.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-72x72.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-76x76.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-76x76.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-76x76.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-76x76.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-precomposed.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-precomposed.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon-precomposed.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-precomposed.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/apple-icon.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-16x16.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-16x16.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-16x16.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-16x16.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-32x32.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-32x32.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-32x32.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-32x32.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-96x96.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-96x96.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon-96x96.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-96x96.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon.ico b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon.ico similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/favicon.ico rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon.ico diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-144x144.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-150x150.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-150x150.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-150x150.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-150x150.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-310x310.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-310x310.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-310x310.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-310x310.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-70x70.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-70x70.png similarity index 100% rename from VirtualGloomhavenBoard/Indigo/wwwroot/img/favicons/ms-icon-70x70.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-70x70.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1a.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1a.png new file mode 100644 index 0000000000000000000000000000000000000000..9fb5ca2bb5fd50cb6faf597b4db55a826fe570f0 GIT binary patch literal 144335 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

%&|nFjUX) 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

;~{JMB4E=Ma|A1mln3I@OdKFBw(&wzvBo@YgvT{ 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

}eQM`u8|2tnZ-=T~bU-#DDb7}3(7Kmz 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 a_C{&Yz=kfY<39W0{Zo)pm9CaF4g7zJIS%pw literal 0 HcmV?d00001 diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/move-icon.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/move-icon.webp new file mode 100644 index 0000000000000000000000000000000000000000..6131a83e398d9f40d8fb1f6e4b3cfee366e54e03 GIT binary patch literal 642 zcmV-|0)72bNk&F`0ssJ4MM6+kP&iC(0ssInEC34-b%sD7X@Bk=A|kEOA&1aNk|Sw& z-u>gST>U?S3kI{(J&VA#{^md6(6(*bxgW7@+jeO?>CBFmRoPByJLzoOwrwYS0_51* zwzko~0G00ChNE-BoOFzRI_6Z=GE}$!uXLitDJ*RqB^Njxg zeX4)2K9FZ8YjY71eR^p=fxaDANq+H~xHa9fze_3-HUCnWI`_vSZ9aurfT#&+iMbX6 z;OHL$ki#;E01P@95VmMo@wFUQmwvS3_qY>)QeDS6SHWxQI1efS;bz%SHdgueAT3j-*XU4Kw%^m%sM z^ow?;Khy-$4Yz+%cTXXrmkqh(ge0nabO)GoD4BP;Ylp8R(u-s8lO0^5U-5W?54b@N zZvmoj%>v>Pexah=_K=`HLZP9|zFz=QD*k)hh8gn#`g;4hf=px7kWr`vay=F>7kEQy zNDwZv`A)l&3RgoCQKUPG4&)k=j6E9(tYFcQd>Dx0F~A++TSKP8PdR@B{7?)}L#Cs{ c&;osEZflf+7bjK40q*;@Qdmjkj5wIKREfPQg#Z8m literal 0 HcmV?d00001 diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/manifest.json b/VirtualGloomhavenBoard/Indigo/wwwroot/static/manifest.json new file mode 100644 index 00000000..683d0f92 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/static/manifest.json @@ -0,0 +1,46 @@ +{ + "name": "Virtual Gloomhaven Board", + "short_name": "Virtual Gloomhaven Board", + "start_url": ".", + "display": "standalone", + "background_color": "#915d42", + "description": "An interactive board to allow players to remotely play Gloomhaven together.", + "icons": [ + { + "src": ".\/img\/favicons\/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": ".\/img\/favicons\/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": ".\/img\/favicons\/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": ".\/img\/favicons\/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": ".\/img\/favicons\/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": ".\/img\/favicons\/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] +} diff --git a/VirtualGloomhavenBoard/Indigo/yarn.lock b/VirtualGloomhavenBoard/Indigo/yarn.lock deleted file mode 100644 index 3b89d6b8..00000000 --- a/VirtualGloomhavenBoard/Indigo/yarn.lock +++ /dev/null @@ -1,2097 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.21.4.tgz#d0fa9e4413aca81f2b23b9442797bda1826edb39" - integrity sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g== - dependencies: - "@babel/highlight" "^7.18.6" - -"@babel/helper-validator-identifier@^7.18.6": - version "7.19.1" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== - -"@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/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/resolve-uri@3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" - integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== - -"@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.3" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" - integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@jridgewell/sourcemap-codec@1.4.14": - version "1.4.14" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" - integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== - -"@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - -"@jridgewell/trace-mapping@^0.3.9": - version "0.3.18" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" - integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - -"@lezer/common@^0.15.0", "@lezer/common@^0.15.7": - version "0.15.12" - resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.12.tgz#2f21aec551dd5fd7d24eb069f90f54d5bc6ee5e9" - integrity sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig== - -"@lezer/lr@^0.15.4": - version "0.15.8" - resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.8.tgz#1564a911e62b0a0f75ca63794a6aa8c5dc63db21" - integrity sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg== - dependencies: - "@lezer/common" "^0.15.0" - -"@lmdb/lmdb-darwin-arm64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz#bc66fa43286b5c082e8fee0eacc17995806b6fbe" - integrity sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A== - -"@lmdb/lmdb-darwin-x64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz#89d8390041bce6bab24a82a20392be22faf54ffc" - integrity sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA== - -"@lmdb/lmdb-linux-arm64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz#14fe4c96c2bb1285f93797f45915fa35ee047268" - integrity sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ== - -"@lmdb/lmdb-linux-arm@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz#05bde4573ab10cf21827339fe687148f2590cfa1" - integrity sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw== - -"@lmdb/lmdb-linux-x64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz#d2f85afd857d2c33d2caa5b057944574edafcfee" - integrity sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q== - -"@lmdb/lmdb-win32-x64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz#28f643fbc0bec30b07fbe95b137879b6b4d1c9c5" - integrity sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA== - -"@microsoft/signalr-protocol-msgpack@^6.0.2": - version "6.0.16" - resolved "https://registry.yarnpkg.com/@microsoft/signalr-protocol-msgpack/-/signalr-protocol-msgpack-6.0.16.tgz#71ad16d1759079e2894d89d53764c48bed467165" - integrity sha512-cEbtkYZ9cmcdxsdYn2N5ZKX6GAgQClYHqe4p9Y7Gs1WyUXSpIXDWM7JLnMuFaoQJDw2Jhh/lizdTUvJUcMKrAQ== - dependencies: - "@microsoft/signalr" ">=6.0.16" - "@msgpack/msgpack" "^2.7.0" - -"@microsoft/signalr@>=6.0.16": - version "7.0.5" - resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-7.0.5.tgz#e7a984ac1f1b6a488170e9cb2f2f46a5d97d5f80" - integrity sha512-j84syCKlXkQAOQhyrzRmW7w/M2UXQ6OKcXXFIVNjmiiZbEGIvSvJDRAuyMFjArdQOXz+etJgd58H/prTbyTCrA== - dependencies: - abort-controller "^3.0.0" - eventsource "^2.0.2" - fetch-cookie "^2.0.3" - node-fetch "^2.6.7" - ws "^7.4.5" - -"@microsoft/signalr@^6.0.2": - version "6.0.16" - resolved "https://registry.yarnpkg.com/@microsoft/signalr/-/signalr-6.0.16.tgz#d36498a9b16bf11c0e9213d77d24c0ad8ebffa47" - integrity sha512-wekzRtt2Ti38Ja0OQwLE0EKN0Zm7RI9VilrungwHe5Eej1IwnRYuhpauAqNtwwP3CY2j7uFT4XUk74E2vythTQ== - dependencies: - abort-controller "^3.0.0" - eventsource "^1.0.7" - fetch-cookie "^0.11.0" - node-fetch "^2.6.7" - ws "^7.4.5" - -"@mischnic/json-sourcemap@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507" - integrity sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA== - dependencies: - "@lezer/common" "^0.15.7" - "@lezer/lr" "^0.15.4" - json5 "^2.2.1" - -"@msgpack/msgpack@^2.7.0": - version "2.8.0" - resolved "https://registry.yarnpkg.com/@msgpack/msgpack/-/msgpack-2.8.0.tgz#4210deb771ee3912964f14a15ddfb5ff877e70b9" - integrity sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ== - -"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz#44d752c1a2dc113f15f781b7cc4f53a307e3fa38" - integrity sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ== - -"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz#f954f34355712212a8e06c465bc06c40852c6bb3" - integrity sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw== - -"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz#45c63037f045c2b15c44f80f0393fa24f9655367" - integrity sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg== - -"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz#35707efeafe6d22b3f373caf9e8775e8920d1399" - integrity sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA== - -"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz#091b1218b66c341f532611477ef89e83f25fae4f" - integrity sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA== - -"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407" - integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ== - -"@parcel/bundler-default@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.8.3.tgz#d64739dbc2dbd59d6629861bf77a8083aced5229" - integrity sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/graph" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - nullthrows "^1.1.1" - -"@parcel/cache@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.8.3.tgz#169e130cf59913c0ed9fadce1a450e68f710e16f" - integrity sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ== - dependencies: - "@parcel/fs" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/utils" "2.8.3" - lmdb "2.5.2" - -"@parcel/codeframe@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.8.3.tgz#84fb529ef70def7f5bc64f6c59b18d24826f5fcc" - integrity sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg== - dependencies: - chalk "^4.1.0" - -"@parcel/compressor-raw@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz#301753df8c6de967553149639e8a4179b88f0c95" - integrity sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg== - dependencies: - "@parcel/plugin" "2.8.3" - -"@parcel/config-default@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.8.3.tgz#9a43486e7c702e96c68052c37b79098d7240e35b" - integrity sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw== - dependencies: - "@parcel/bundler-default" "2.8.3" - "@parcel/compressor-raw" "2.8.3" - "@parcel/namer-default" "2.8.3" - "@parcel/optimizer-css" "2.8.3" - "@parcel/optimizer-htmlnano" "2.8.3" - "@parcel/optimizer-image" "2.8.3" - "@parcel/optimizer-svgo" "2.8.3" - "@parcel/optimizer-terser" "2.8.3" - "@parcel/packager-css" "2.8.3" - "@parcel/packager-html" "2.8.3" - "@parcel/packager-js" "2.8.3" - "@parcel/packager-raw" "2.8.3" - "@parcel/packager-svg" "2.8.3" - "@parcel/reporter-dev-server" "2.8.3" - "@parcel/resolver-default" "2.8.3" - "@parcel/runtime-browser-hmr" "2.8.3" - "@parcel/runtime-js" "2.8.3" - "@parcel/runtime-react-refresh" "2.8.3" - "@parcel/runtime-service-worker" "2.8.3" - "@parcel/transformer-babel" "2.8.3" - "@parcel/transformer-css" "2.8.3" - "@parcel/transformer-html" "2.8.3" - "@parcel/transformer-image" "2.8.3" - "@parcel/transformer-js" "2.8.3" - "@parcel/transformer-json" "2.8.3" - "@parcel/transformer-postcss" "2.8.3" - "@parcel/transformer-posthtml" "2.8.3" - "@parcel/transformer-raw" "2.8.3" - "@parcel/transformer-react-refresh-wrap" "2.8.3" - "@parcel/transformer-svg" "2.8.3" - -"@parcel/core@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.8.3.tgz#22a69f36095d53736ab10bf42697d9aa5f4e382b" - integrity sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ== - dependencies: - "@mischnic/json-sourcemap" "^0.1.0" - "@parcel/cache" "2.8.3" - "@parcel/diagnostic" "2.8.3" - "@parcel/events" "2.8.3" - "@parcel/fs" "2.8.3" - "@parcel/graph" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/package-manager" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" - abortcontroller-polyfill "^1.1.9" - base-x "^3.0.8" - browserslist "^4.6.6" - clone "^2.1.1" - dotenv "^7.0.0" - dotenv-expand "^5.1.0" - json5 "^2.2.0" - msgpackr "^1.5.4" - nullthrows "^1.1.1" - semver "^5.7.1" - -"@parcel/diagnostic@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.8.3.tgz#d560276d5d2804b48beafa1feaf3fc6b2ac5e39d" - integrity sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ== - dependencies: - "@mischnic/json-sourcemap" "^0.1.0" - nullthrows "^1.1.1" - -"@parcel/events@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.8.3.tgz#205f8d874e6ecc2cbdb941bf8d54bae669e571af" - integrity sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w== - -"@parcel/fs-search@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.8.3.tgz#1c7d812c110b808758f44c56e61dfffdb09e9451" - integrity sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ== - dependencies: - detect-libc "^1.0.3" - -"@parcel/fs@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.8.3.tgz#80536afe877fc8a2bd26be5576b9ba27bb4c5754" - integrity sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ== - dependencies: - "@parcel/fs-search" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/watcher" "^2.0.7" - "@parcel/workers" "2.8.3" - -"@parcel/graph@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.8.3.tgz#00ffe8ec032e74fee57199e54529f1da7322571d" - integrity sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg== - dependencies: - nullthrows "^1.1.1" - -"@parcel/hash@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.8.3.tgz#bc2499a27395169616cad2a99e19e69b9098f6e9" - integrity sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw== - dependencies: - detect-libc "^1.0.3" - xxhash-wasm "^0.4.2" - -"@parcel/logger@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.8.3.tgz#e14e4debafb3ca9e87c07c06780f9afc38b2712c" - integrity sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/events" "2.8.3" - -"@parcel/markdown-ansi@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz#1337d421bb1133ad178f386a8e1b746631bba4a1" - integrity sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ== - dependencies: - chalk "^4.1.0" - -"@parcel/namer-default@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.8.3.tgz#5304bee74beb4b9c1880781bdbe35be0656372f4" - integrity sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - nullthrows "^1.1.1" - -"@parcel/node-resolver-core@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz#581df074a27646400b3fed9da95297b616a7db8f" - integrity sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/utils" "2.8.3" - nullthrows "^1.1.1" - semver "^5.7.1" - -"@parcel/optimizer-css@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz#420a333f4b78f7ff15e69217dfed34421b1143ee" - integrity sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" - browserslist "^4.6.6" - lightningcss "^1.16.1" - nullthrows "^1.1.1" - -"@parcel/optimizer-htmlnano@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz#a71ab6f0f24160ef9f573266064438eff65e96d0" - integrity sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg== - dependencies: - "@parcel/plugin" "2.8.3" - htmlnano "^2.0.0" - nullthrows "^1.1.1" - posthtml "^0.16.5" - svgo "^2.4.0" - -"@parcel/optimizer-image@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz#ea49b4245b4f7d60b38c7585c6311fb21d341baa" - integrity sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" - detect-libc "^1.0.3" - -"@parcel/optimizer-svgo@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz#04da4efec6b623679539a84961bff6998034ba8a" - integrity sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - svgo "^2.4.0" - -"@parcel/optimizer-terser@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz#3a06d98d09386a1a0ae1be85376a8739bfba9618" - integrity sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" - nullthrows "^1.1.1" - terser "^5.2.0" - -"@parcel/package-manager@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.8.3.tgz#ddd0d62feae3cf0fb6cc0537791b3a16296ad458" - integrity sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/fs" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" - semver "^5.7.1" - -"@parcel/packager-css@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.8.3.tgz#0eff34268cb4f5dfb53c1bbca85f5567aeb1835a" - integrity sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" - nullthrows "^1.1.1" - -"@parcel/packager-html@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.8.3.tgz#f9263b891aa4dd46c6e2fa2b07025a482132fff1" - integrity sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - nullthrows "^1.1.1" - posthtml "^0.16.5" - -"@parcel/packager-js@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.8.3.tgz#3ed11565915d73d12192b6901c75a6b820e4a83a" - integrity sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" - globals "^13.2.0" - nullthrows "^1.1.1" - -"@parcel/packager-raw-url@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-raw-url/-/packager-raw-url-2.8.3.tgz#5994dca47f37a395deb0fd5b574a9d4656617f47" - integrity sha512-v8k/x2pnR3DDiIJrPTUcBd+MjH9ocpac0dsdJ02yeyGIQTecqL6nuCtu6W4m75CC7vFjjh/aCK9TJsOHOFnCFQ== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - -"@parcel/packager-raw@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.8.3.tgz#bdec826df991e186cb58691cc45d12ad5c06676e" - integrity sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA== - dependencies: - "@parcel/plugin" "2.8.3" - -"@parcel/packager-svg@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.8.3.tgz#7233315296001c531cb55ca96b5f2ef672343630" - integrity sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - posthtml "^0.16.4" - -"@parcel/plugin@2.8.3", "@parcel/plugin@^2.0.0-beta.1": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.8.3.tgz#7bb30a5775eaa6473c27f002a0a3ee7308d6d669" - integrity sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw== - dependencies: - "@parcel/types" "2.8.3" - -"@parcel/reporter-cli@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz#12a4743b51b8fe6837f53c20e01bbf1f7336e8e4" - integrity sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - chalk "^4.1.0" - term-size "^2.2.1" - -"@parcel/reporter-dev-server@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz#a0daa5cc015642684cea561f4e0e7116bbffdc1c" - integrity sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - -"@parcel/resolver-default@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.8.3.tgz#5ae41e537ae4a793c1abb47f094482b9e2ac3535" - integrity sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A== - dependencies: - "@parcel/node-resolver-core" "2.8.3" - "@parcel/plugin" "2.8.3" - -"@parcel/runtime-browser-hmr@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz#1fa74e1fbd1030b0a920c58afa3a9eb7dc4bcd1e" - integrity sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - -"@parcel/runtime-js@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.8.3.tgz#0baa4c8fbf77eabce05d01ccc186614968ffc0cd" - integrity sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - nullthrows "^1.1.1" - -"@parcel/runtime-react-refresh@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz#381a942fb81e8f5ac6c7e0ee1b91dbf34763c3f8" - integrity sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - react-error-overlay "6.0.9" - react-refresh "^0.9.0" - -"@parcel/runtime-service-worker@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz#54d92da9ff1dfbd27db0e84164a22fa59e99b348" - integrity sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - nullthrows "^1.1.1" - -"@parcel/source-map@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.1.tgz#fb193b82dba6dd62cc7a76b326f57bb35000a782" - integrity sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew== - dependencies: - detect-libc "^1.0.3" - -"@parcel/transformer-babel@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz#286bc6cb9afe4c0259f0b28e0f2f47322a24b130" - integrity sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" - browserslist "^4.6.6" - json5 "^2.2.0" - nullthrows "^1.1.1" - semver "^5.7.0" - -"@parcel/transformer-css@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.8.3.tgz#d6c44100204e73841ad8e0f90472172ea8b9120c" - integrity sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" - browserslist "^4.6.6" - lightningcss "^1.16.1" - nullthrows "^1.1.1" - -"@parcel/transformer-html@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.8.3.tgz#5c68b28ee6b8c7a13b8aee87f7957ad3227bd83f" - integrity sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" - nullthrows "^1.1.1" - posthtml "^0.16.5" - posthtml-parser "^0.10.1" - posthtml-render "^3.0.0" - semver "^5.7.1" - srcset "4" - -"@parcel/transformer-image@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.8.3.tgz#73805b2bfc3c8919d7737544e5f8be39e3f303fe" - integrity sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" - nullthrows "^1.1.1" - -"@parcel/transformer-js@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.8.3.tgz#fe400df428394d1e7fe5afb6dea5c7c858e44f03" - integrity sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" - "@swc/helpers" "^0.4.12" - browserslist "^4.6.6" - detect-libc "^1.0.3" - nullthrows "^1.1.1" - regenerator-runtime "^0.13.7" - semver "^5.7.1" - -"@parcel/transformer-json@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.8.3.tgz#25deb3a5138cc70a83269fc5d39d564609354d36" - integrity sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg== - dependencies: - "@parcel/plugin" "2.8.3" - json5 "^2.2.0" - -"@parcel/transformer-postcss@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz#df4fdc1c90893823445f2a8eb8e2bdd0349ccc58" - integrity sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - clone "^2.1.1" - nullthrows "^1.1.1" - postcss-value-parser "^4.2.0" - semver "^5.7.1" - -"@parcel/transformer-posthtml@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz#7c3912a5a631cb26485f6464e0d6eeabb6f1e718" - integrity sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - nullthrows "^1.1.1" - posthtml "^0.16.5" - posthtml-parser "^0.10.1" - posthtml-render "^3.0.0" - semver "^5.7.1" - -"@parcel/transformer-raw@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz#3a22213fe18a5f83fd78889cb49f06e059cfead7" - integrity sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ== - dependencies: - "@parcel/plugin" "2.8.3" - -"@parcel/transformer-react-refresh-wrap@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz#8b0392638405dd470a886002229f7889d5464822" - integrity sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - react-refresh "^0.9.0" - -"@parcel/transformer-sass@^2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-sass/-/transformer-sass-2.8.3.tgz#d3a0388e77c1e6279b488ccd0abf612d3a0897ff" - integrity sha512-ak196rjvXdsBOGi5aTkBEKv6i4LKQgOkHuaKEjeT8g2a3CU6Z36J+j2GbZzsznfws/hH+CRTf8bAsbkxtKlkjQ== - dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/source-map" "^2.1.1" - sass "^1.38.0" - -"@parcel/transformer-svg@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz#4df959cba4ebf45d7aaddd540f752e6e84df38b2" - integrity sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" - nullthrows "^1.1.1" - posthtml "^0.16.5" - posthtml-parser "^0.10.1" - posthtml-render "^3.0.0" - semver "^5.7.1" - -"@parcel/transformer-webmanifest@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-webmanifest/-/transformer-webmanifest-2.8.3.tgz#5858079bf5abaedcf42dc5e856248a596277dc71" - integrity sha512-v3NuQc1K1AMfD1+hvh/YYpxBEin52CvEX94MnjwYK6bDmJ35rNuttIs7T6DZxAOopRbGwoTchCShIbv15gTcvg== - dependencies: - "@mischnic/json-sourcemap" "^0.1.0" - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - -"@parcel/types@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.8.3.tgz#3306bc5391b6913bd619914894b8cd84a24b30fa" - integrity sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw== - dependencies: - "@parcel/cache" "2.8.3" - "@parcel/diagnostic" "2.8.3" - "@parcel/fs" "2.8.3" - "@parcel/package-manager" "2.8.3" - "@parcel/source-map" "^2.1.1" - "@parcel/workers" "2.8.3" - utility-types "^3.10.0" - -"@parcel/utils@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.8.3.tgz#0d56c9e8e22c119590a5e044a0e01031965da40e" - integrity sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA== - dependencies: - "@parcel/codeframe" "2.8.3" - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/markdown-ansi" "2.8.3" - "@parcel/source-map" "^2.1.1" - chalk "^4.1.0" - -"@parcel/watcher@^2.0.7": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.1.0.tgz#5f32969362db4893922c526a842d8af7a8538545" - integrity sha512-8s8yYjd19pDSsBpbkOHnT6Z2+UJSuLQx61pCFM0s5wSRvKCEMDjd/cHY3/GI1szHIWbpXpsJdg3V6ISGGx9xDw== - dependencies: - is-glob "^4.0.3" - micromatch "^4.0.5" - node-addon-api "^3.2.1" - node-gyp-build "^4.3.0" - -"@parcel/workers@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.8.3.tgz#255450ccf4db234082407e4ddda5fd575f08c235" - integrity sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - chrome-trace-event "^1.0.2" - nullthrows "^1.1.1" - -"@swc/helpers@^0.4.12": - version "0.4.14" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74" - integrity sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw== - dependencies: - tslib "^2.4.0" - -"@trysound/sax@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" - integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== - -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - -abortcontroller-polyfill@^1.1.9: - version "1.7.5" - resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" - integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== - -acorn@^8.5.0: - version "8.8.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - -base-x@^3.0.8: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - -base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.0.0, bn.js@^5.1.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - -boolbase@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== - -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" - -brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -browserslist@^4.6.6: - version "4.21.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" - integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== - dependencies: - caniuse-lite "^1.0.30001449" - electron-to-chromium "^1.4.284" - node-releases "^2.0.8" - update-browserslist-db "^1.0.10" - -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-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== - -buffer@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -caniuse-lite@^1.0.30001449: - version "1.0.30001481" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz#f58a717afe92f9e69d0e35ff64df596bfad93912" - integrity sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ== - -chalk@^2.0.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -"chokidar@>=3.0.0 <4.0.0": - 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" - -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -clone@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -commander@^7.0.0, commander@^7.2.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== - -cosmiconfig@^8.0.0: - version "8.1.3" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.1.3.tgz#0e614a118fcc2d9e5afc2f87d53cd09931015689" - integrity sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw== - dependencies: - import-fresh "^3.2.1" - js-yaml "^4.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - -create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -crypto-browserify@^3.12.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-select@^4.1.3: - version "4.3.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" - integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== - dependencies: - boolbase "^1.0.0" - css-what "^6.0.1" - domhandler "^4.3.1" - domutils "^2.8.0" - nth-check "^2.0.1" - -css-tree@^1.1.2, css-tree@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" - integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== - dependencies: - mdn-data "2.0.14" - source-map "^0.6.1" - -css-what@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" - integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== - -csso@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" - integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== - dependencies: - css-tree "^1.1.2" - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -detect-libc@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dom-serializer@^1.0.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" - integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.0" - entities "^2.0.0" - -domelementtype@^2.0.1, domelementtype@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - -domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" - integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== - dependencies: - domelementtype "^2.2.0" - -domutils@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" - integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== - dependencies: - dom-serializer "^1.0.1" - domelementtype "^2.2.0" - domhandler "^4.2.0" - -dotenv-expand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" - integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== - -dotenv@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" - integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== - -electron-to-chromium@^1.4.284: - version "1.4.372" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.372.tgz#7888ac92ccb9556627c3a37eba3b89ee5ac345f8" - integrity sha512-MrlFq/j+TYHOjeWsWGYfzevc25HNeJdsF6qaLFrqBTRWZQtWkb1myq/Q2veLWezVaa5OcSZ99CFwTT4aF4Mung== - -elliptic@^6.5.3: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - -entities@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4" - integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-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 sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -events@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - -eventsource@^1.0.7: - version "1.1.2" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.2.tgz#bc75ae1c60209e7cb1541231980460343eaea7c2" - integrity sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA== - -eventsource@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508" - integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -fetch-cookie@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.11.0.tgz#e046d2abadd0ded5804ce7e2cae06d4331c15407" - integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== - dependencies: - tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" - -fetch-cookie@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-2.1.0.tgz#6e127909912f9e527533b045aab555c06b33801b" - integrity sha512-39+cZRbWfbibmj22R2Jy6dmTbAWC+oqun1f1FzQaNurkPDUP4C38jpeZbiXCR88RKRVDp8UcDrbFXkNhN+NjYg== - dependencies: - set-cookie-parser "^2.4.8" - tough-cookie "^4.0.0" - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -get-port@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" - integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== - -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -globals@^13.2.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== - dependencies: - type-fest "^0.20.2" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -htmlnano@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-2.0.4.tgz#315108063ed0bb6a16ccb53ad1b601f02d3fe721" - integrity sha512-WGCkyGFwjKW1GeCBsPYacMvaMnZtFJ0zIRnC2NCddkA+IOEhTqskXrS7lep+3yYZw/nQ3dW1UAX4yA/GJyR8BA== - dependencies: - cosmiconfig "^8.0.0" - posthtml "^0.16.5" - timsort "^0.3.0" - -htmlparser2@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-7.2.0.tgz#8817cdea38bbc324392a90b1990908e81a65f5a5" - integrity sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog== - dependencies: - domelementtype "^2.0.1" - domhandler "^4.2.2" - domutils "^2.8.0" - entities "^3.0.1" - -ieee754@^1.1.13: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -immutable@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be" - integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg== - -import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -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" - -is-json@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff" - integrity sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA== - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^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" - -json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - -json5@^2.2.0, json5@^2.2.1: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - -lightningcss-darwin-arm64@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.20.0.tgz#0416a0cb840944ea4aee972df02491c0168a784c" - integrity sha512-aYEohJTlzwB8URJaNiS57tMbjyLub0mYvxlxKQk8SZv+irXx6MoBWpDNQKKTS9gg1pGf/eAwjpa3BLAoCBsh1A== - -lightningcss-darwin-x64@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.20.0.tgz#4caa2b38fe223eabb32ebc3e1268a6b09e6b8d06" - integrity sha512-cmMgY8FFWVaGgtift7eKKkHMqlz9O09/yTdlCXEDOeDP9yeo6vHOBTRP7ojb368kjw8Ew3l0L2uT1Gtx56eNkg== - -lightningcss-linux-arm-gnueabihf@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.20.0.tgz#3e999a07aa77c10a06c9dda9b507c7a737f8521f" - integrity sha512-/m+NDO1O6JCv7R9F0XWlXcintQHx4MPNU+kt8jZJO07LLdGwCfvjN31GVcwVPlStnnx/cU8uTTmax6g/Qu/whg== - -lightningcss-linux-arm64-gnu@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.20.0.tgz#8b7786936ea462f744a85038fb033cc56049b677" - integrity sha512-gtXoa6v0HvMRLbev6Hsef0+Q5He7NslB+Rs7G49Y5LUSdJeGIATEN+j8JzHC0DnxCsOGbEgGRmvtJzzYDkkluw== - -lightningcss-linux-arm64-musl@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.20.0.tgz#8d812309c4e70398cee79fcdc452548ca521a6eb" - integrity sha512-Po7XpucM1kZnkiyd2BNwTExSDcZ8jm8uB9u+Sq44qjpkf5f75jreQwn3DQm9I1t5C6tB9HGt30HExMju9umJBQ== - -lightningcss-linux-x64-gnu@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.20.0.tgz#7652fbb26e50a5fa21b763aaebdb4bc657540c7e" - integrity sha512-8yR/fGNn/P0I+Lc3PK+VWPET/zdSpBfHFIG0DJ38TywMbItVKvnFvoTBwnIm4LqBz7g2G2dDexnNP95za2Ll8g== - -lightningcss-linux-x64-musl@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.20.0.tgz#aa21957fc51c363b4436e973911d01af4bed3c35" - integrity sha512-EmpJ+VkPZ8RACiB4m+l8TmapmE1W2UvJKDHE+ML/3Ihr9tRKUs3CibfnQTFZC8aSsrxgXagDAN+PgCDDhIyriA== - -lightningcss-win32-x64-msvc@1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.20.0.tgz#dcec3f7e03deda94504c93a9a03aec0484a5d5eb" - integrity sha512-BRdPvbq7Cc1qxAzp2emqWJHrqsEkf4ggxS29VOnxT7jhkdHKU+a26OVMjvm/OL0NH0ToNOZNAPvHMSexiEgBeA== - -lightningcss@^1.16.1: - version "1.20.0" - resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.20.0.tgz#efa36a52feae9b0c8537c8e650a7819f549a4a23" - integrity sha512-4bj8aP+Vi+or8Gwq/hknmicr4PmA8D9uL/3qY0N0daX5vYBMYERGI6Y93nzoeRgQMULq+gtrN/FvJYtH0xNN8g== - dependencies: - detect-libc "^1.0.3" - optionalDependencies: - lightningcss-darwin-arm64 "1.20.0" - lightningcss-darwin-x64 "1.20.0" - lightningcss-linux-arm-gnueabihf "1.20.0" - lightningcss-linux-arm64-gnu "1.20.0" - lightningcss-linux-arm64-musl "1.20.0" - lightningcss-linux-x64-gnu "1.20.0" - lightningcss-linux-x64-musl "1.20.0" - lightningcss-win32-x64-msvc "1.20.0" - -lines-and-columns@^1.1.6: - version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" - integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== - -lmdb@2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.5.2.tgz#37e28a9fb43405f4dc48c44cec0e13a14c4a6ff1" - integrity sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA== - dependencies: - msgpackr "^1.5.4" - node-addon-api "^4.3.0" - node-gyp-build-optional-packages "5.0.3" - ordered-binary "^1.2.4" - weak-lru-cache "^1.2.2" - optionalDependencies: - "@lmdb/lmdb-darwin-arm64" "2.5.2" - "@lmdb/lmdb-darwin-x64" "2.5.2" - "@lmdb/lmdb-linux-arm" "2.5.2" - "@lmdb/lmdb-linux-arm64" "2.5.2" - "@lmdb/lmdb-linux-x64" "2.5.2" - "@lmdb/lmdb-win32-x64" "2.5.2" - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -mdn-data@2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" - integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== - -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" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - -msgpackr-extract@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz#e05ec1bb4453ddf020551bcd5daaf0092a2c279d" - integrity sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A== - dependencies: - node-gyp-build-optional-packages "5.0.7" - optionalDependencies: - "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.2" - "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.2" - "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.2" - "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.2" - "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" - "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" - -msgpackr@^1.5.4: - version "1.8.5" - resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.8.5.tgz#8cadfb935357680648f33699d0e833c9179dbfeb" - integrity sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg== - optionalDependencies: - msgpackr-extract "^3.0.1" - -node-addon-api@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" - integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== - -node-addon-api@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" - integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== - -node-fetch@^2.6.7: - version "2.6.9" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" - integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== - dependencies: - whatwg-url "^5.0.0" - -node-gyp-build-optional-packages@5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" - integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== - -node-gyp-build-optional-packages@5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3" - integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w== - -node-gyp-build@^4.3.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" - integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== - -node-releases@^2.0.8: - version "2.0.10" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" - integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -nth-check@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" - integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== - dependencies: - boolbase "^1.0.0" - -nullthrows@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" - integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== - -ordered-binary@^1.2.4: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.4.0.tgz#6bb53d44925f3b8afc33d1eed0fa15693b211389" - integrity sha512-EHQ/jk4/a9hLupIKxTfUsQRej1Yd/0QLQs3vGvIqg5ZtCYSzNhkzHoZc7Zf4e4kUlDaC3Uw8Q/1opOLNN2OKRQ== - -parcel-reporter-static-files-copy@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/parcel-reporter-static-files-copy/-/parcel-reporter-static-files-copy-1.5.0.tgz#8ca7d7e4d1f0f52c30853117403696decf64da24" - integrity sha512-dsY3MQkbYSgEqS0/22vtD2mZtel8UC0ItH0ok8LmgFeCMTsdhyOtJgvt945ODIzu9lYc/sCIzksM8C77uSE3Fg== - dependencies: - "@parcel/plugin" "^2.0.0-beta.1" - -parcel@^2.8.3: - version "2.8.3" - resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.8.3.tgz#1ff71d7317274fd367379bc7310a52c6b75d30c2" - integrity sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA== - dependencies: - "@parcel/config-default" "2.8.3" - "@parcel/core" "2.8.3" - "@parcel/diagnostic" "2.8.3" - "@parcel/events" "2.8.3" - "@parcel/fs" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/package-manager" "2.8.3" - "@parcel/reporter-cli" "2.8.3" - "@parcel/reporter-dev-server" "2.8.3" - "@parcel/utils" "2.8.3" - chalk "^4.1.0" - commander "^7.0.0" - get-port "^4.2.0" - v8-compile-cache "^2.0.0" - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-json@^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" - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -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.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -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== - -posthtml-parser@^0.10.1: - version "0.10.2" - resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.10.2.tgz#df364d7b179f2a6bf0466b56be7b98fd4e97c573" - integrity sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg== - dependencies: - htmlparser2 "^7.1.1" - -posthtml-parser@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.11.0.tgz#25d1c7bf811ea83559bc4c21c189a29747a24b7a" - integrity sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw== - dependencies: - htmlparser2 "^7.1.1" - -posthtml-render@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-3.0.0.tgz#97be44931496f495b4f07b99e903cc70ad6a3205" - integrity sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA== - dependencies: - is-json "^2.0.1" - -posthtml@^0.16.4, posthtml@^0.16.5: - version "0.16.6" - resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.16.6.tgz#e2fc407f67a64d2fa3567afe770409ffdadafe59" - integrity sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ== - dependencies: - posthtml-parser "^0.11.0" - posthtml-render "^3.0.0" - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== - -psl@^1.1.33: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -punycode@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== - -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -react-error-overlay@6.0.9: - version "6.0.9" - resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a" - integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew== - -react-refresh@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" - integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== - -readable-stream@^3.5.0, readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -regenerator-runtime@^0.13.7: - version "0.13.11" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safer-buffer@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sass@^1.38.0: - version "1.62.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.62.1.tgz#caa8d6bf098935bc92fc73fa169fb3790cacd029" - integrity sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A== - dependencies: - chokidar ">=3.0.0 <4.0.0" - immutable "^4.0.0" - source-map-js ">=0.6.2 <2.0.0" - -semver@^5.7.0, semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -set-cookie-parser@^2.4.8: - version "2.6.0" - resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51" - integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -"source-map-js@>=0.6.2 <2.0.0": - 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.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.6.0, source-map@^0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -srcset@4: - version "4.0.0" - resolved "https://registry.yarnpkg.com/srcset/-/srcset-4.0.0.tgz#336816b665b14cd013ba545b6fe62357f86e65f4" - integrity sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw== - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -stream-browserify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" - integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== - dependencies: - inherits "~2.0.4" - readable-stream "^3.5.0" - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -svgo@^2.4.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" - integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== - dependencies: - "@trysound/sax" "0.2.0" - commander "^7.2.0" - css-select "^4.1.3" - css-tree "^1.1.3" - csso "^4.2.0" - picocolors "^1.0.0" - stable "^0.1.8" - -term-size@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" - integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== - -terser@^5.2.0: - version "5.17.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.1.tgz#948f10830454761e2eeedc6debe45c532c83fd69" - integrity sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw== - dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" - commander "^2.20.0" - source-map-support "~0.5.20" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A== - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0", tough-cookie@^4.0.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.2.tgz#e53e84b85f24e0b65dd526f46628db6c85f6b874" - integrity sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -tslib@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - -update-browserslist-db@^1.0.10: - version "1.0.11" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - -url-parse@^1.5.3: - version "1.5.10" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -util-deprecate@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -utility-types@^3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" - integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== - -v8-compile-cache@^2.0.0: - 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== - -weak-lru-cache@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz#fdbb6741f36bae9540d12f480ce8254060dccd19" - integrity sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -ws@^7.4.5: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== - -xxhash-wasm@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79" - integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA== From 9c3429a7b1b927173a41c7f3301c33411b644d6e Mon Sep 17 00:00:00 2001 From: David North Date: Fri, 5 May 2023 21:27:33 +0100 Subject: [PATCH 28/60] Updates tooling with keyboard events --- tooling.html | 78 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/tooling.html b/tooling.html index b5005322..292354b9 100644 --- a/tooling.html +++ b/tooling.html @@ -56,7 +56,6 @@ button { width: 30px; } - + + diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss new file mode 100644 index 00000000..23557ba2 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss @@ -0,0 +1,114 @@ +.context-menu { + position: absolute; + border-image: url('../static/img/border.webp') 0 fill; + background-color: transparent; + border-style: solid; + padding: 1.4rem; + z-index: 1; + opacity: 0; + transition: opacity 0.3s; + visibility: hidden; + width: 14rem; + transition: 0.15s opacity; + + &.open { + opacity: 1; + visibility: visible; + } + + nav { + ul { + list-style: none; + padding: 0; + margin: 0.8rem 0 0 0; + + li { + padding: 0.2rem 1rem; + border-radius: 0.2rem; + position: relative; + + &:hover { + cursor: pointer; + background-color: rgba(0, 0, 0, 0.2) + } + + &.has-sub-menu { + &:after { + content: '\25BA'; + font-size: 0.6rem; + position: absolute; + right: 0.6rem; + top: 0.4rem; + } + + div { + visibility: hidden; + position: absolute; + right: -7.1rem; + border-image: url('../static/img/border.webp') 0 fill; + background-color: transparent; + border-style: solid; + padding: 1.4rem; + z-index: 2; + top: -0.9rem; + border-radius: 0.2rem; + max-height: 15rem; + + ul { + max-height: 11rem; + overflow-y: auto; + min-width: 5rem; + + li { + padding: 0.2rem 1.3rem; + + &:hover { + cursor: pointer; + background-color: rgba(0, 0, 0, 0.2) + } + + &.selected { + &:after { + content: '\2713'; + font-size: 1.1rem; + position: absolute; + left: 0rem; + top: 0.2rem; + } + } + } + } + } + + &:hover { + div { + visibility: visible; + } + } + } + + &.cancel { + display: none; + } + + &.cancel-menu, + ul li.cancel-menu, + &:not([class^="remove"])+[class^="remove"] { + margin-top: 0.7rem; + + &:before { + content: " "; + display: block; + height: 1px; + width: 75%; + border: 1px solid #888; + background-color: #333; + position: absolute; + left: 1rem; + top: -0.4rem; + } + } + } + } + } +} diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss new file mode 100644 index 00000000..aafa1c8f --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss @@ -0,0 +1,173 @@ +@use 'mixins'; + +html { + .content.scenario-creator { + header { + .title { + input { + text-align: center; + font-size: 2rem; + color: #aaa; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; + font-family: "PirateOne", Nyala, Georgia, serif; + background-color: transparent; + border: none; + outline: none; + width: 38rem; + + &:focus { + outline: grey solid 1px; + } + + &::placeholder { + opacity: 1; + } + } + } + } + + .main { + .page-shadow { + height: 100%; + width: 1rem; + -webkit-box-shadow: 5px 0px 15px 9px rgba(0, 0, 0, 0.65); + -moz-box-shadow: 5px 0px 15px 9px rgba(0, 0, 0, 0.65); + box-shadow: 18px 0px 35px 9px rgb(0, 0, 0); + position: absolute; + left: 7.1rem; + z-index: 1; + } + + .action-list { + flex-direction: column; + flex-wrap: nowrap; + align-items: center; + justify-content: flex-start; + padding-bottom: 1rem; + width: 10.5rem; + @include mixins.mask(url('../static/img/page-mask.webp'), alpha, top right); + @include mixins.mask-repeat(repeat-y); + + section { + display: flex; + flex-direction: column; + min-height: 0; + flex-basis: 4rem; + width: 100%; + transition: flex-basis 0.25s; + + header { + flex-basis: 1rem; + padding: 0.2rem 0 0.75rem 1rem; + background-image: url('../static/img/accordian-banner.webp'); + background-repeat: no-repeat; + background-size: cover; + background-position-y: -0.5rem; + color: #fff; + + &:before { + content: ''; + display: block; + position: absolute; + width: 100%; + height: 1.7rem; + -webkit-box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.75); + -moz-box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.75); + box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.75); + left: 0; + z-index: -1; + } + + &:hover { + cursor: pointer; + } + } + + ul { + list-style: none; + visibility: hidden; + margin: 0; + padding: 0; + overflow: hidden; + -webkit-box-shadow: inset 0px -5px 5px 0px rgba(0, 0, 0, 0.75); + -moz-box-shadow: inset 0px -5px 5px 0px rgba(0, 0, 0, 0.75); + box-shadow: inset 0px -5px 5px 0px rgba(0, 0, 0, 0.75); + width: 9.6rem; + text-align: center; + + li { + padding: 0.2rem 1.2rem; + + img { + max-width: 45px; + } + + .token { + transform: scale(0.85); + top: 0; + left: 33px; + } + + &.size-3 { + img { + position: relative; + + &:first-child, + &:nth-child(2) { + top: 31px; + } + + &:last-child { + top: -66px; + } + } + } + } + + &.map-tiles { + li { + img { + max-width: 90px; + } + } + } + + &.monsters { + li { + div.monster { + position: relative; + max-width: 45px; + @include mixins.mask(null, null, null, 45px); + height: auto; + display: inline-block; + + &:after { + display: none; + } + + img { + max-width: 45px; + height: auto; + } + + span { + display: none; + } + } + } + } + } + + &.active { + flex-basis: 100%; + + ul { + overflow-y: scroll; + visibility: visible; + } + } + } + } + } + } +} diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_form.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_form.scss new file mode 100644 index 00000000..af0245a6 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_form.scss @@ -0,0 +1,147 @@ +.input-wrapper { + display: flex; + flex-direction: column; + margin-bottom: 1.6rem; + position: relative; + + label { + font-size: 1.3rem; + padding-bottom: 0.3rem; + } + + input:not([type="checkbox"]) { + border-radius: 0; + background-color: rgba(0, 0, 0, 0); + border-color: #000; + border-width: 1px; + padding: 0.4rem; + font-size: 1.1rem; + outline: none; + background-color: rgba(49, 40, 38, 0.7); + color: #aaa; + + &:focus { + border-color: #ccc; + -webkit-box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.75); + -moz-box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.75); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.75); + } + } + + label { + position: relative; + + input[type="color"] { + padding: 0; + width: 1.5rem; + float: right; + } + + &.checkbox { + cursor: pointer; + + input[type="checkbox"] { + visibility: hidden; + } + + &:before { + content: ''; + width: 1rem; + height: 1rem; + display: block; + border: 2px solid #563e25; + position: absolute; + top: 0.1rem; + right: 0; + } + + &:after { + content: ""; + width: 16px; + height: 16px; + display: block; + position: absolute; + top: 0.1rem; + right: 0; + box-sizing: content-box; + background-image: url('../static/img/icons.webp'); + background-size: 128px; + background-position: -72px -24px; + transform: scale(1.4); + filter: grayscale(20%); + opacity: 0; + transition: 0.2s; + } + + &.checked:after { + opacity: 1; + } + } + } + + &.error { + .error-label { + position: absolute; + font-family: Arial, Helvetica, sans-serif; + letter-spacing: 0; + line-height: 1.5rem; + text-shadow: 0 0; + font-weight: bold; + color: red; + bottom: -1.4rem; + overflow: hidden; + text-overflow: ellipsis; + max-height: 1.3rem; + max-width: 100%; + } + } +} + +.select-wrapper { + display: flex; + flex-direction: column; + margin-bottom: 1.6rem; + position: relative; + + label { + font-size: 1.3rem; + padding-bottom: 0.3rem; + } + + select { + border-radius: 0; + background-color: rgba(0, 0, 0, 0); + border-color: #000; + border-width: 1px; + padding: 0.4rem; + font-size: 1.1rem; + outline: none; + background-color: rgba(49, 40, 38, 0.7); + color: #aaa; + + &:focus { + border-color: #ccc; + -webkit-box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.75); + -moz-box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.75); + box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.75); + } + } +} + +.button-wrapper { + display: flex; + justify-content: space-between; + align-items: center; + + button { + border-radius: 0; + border-radius: 0; + font-size: 1rem; + padding: 10px; + width: 80px; + border: 2px solid #604729; + background: #a68f7a; + color: #93292e; + font-family: "PirateOne", Nyala, Georgia, serif; + } +} diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_icons.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_icons.scss new file mode 100644 index 00000000..b66c59b8 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_icons.scss @@ -0,0 +1,94 @@ +i { + display: inline-block; + font-size: 0; + text-indent: -99999em; + margin-right: 1rem; + height: 4.5rem; + + &.icon { + &:before { + content: ""; + display: block; + width: 45px; + height: 45px; + background-image: url("../static/img/characters/icons.webp"); + background-size: 256px; + filter: contrast(0%) brightness(130%) drop-shadow(1px 1px black); + top: 0.7rem; + position: relative; + } + + &.brute:before { + background-position: -90px 1px; + top: 0.4rem; + } + + &.tinkerer:before { + background-position: -45px -90px; + } + + &.scoundrel:before { + background-position: -135px -90px; + } + + &.cragheart:before { + background-position: -45px -135px; + } + + &.mindthief:before { + background-position: 0 -45px; + } + + &.spellweaver:before { + background-position: -135px -45px; + } + + &.diviner:before { + background-position: -90px -135px; + } + + &.phoenix-face:before { + background-position: 0 0; + } + + &.lightning-bolt:before { + background-position: -45px 0; + } + + &.angry-face:before { + background-position: -135px 0; + } + + &.triforce:before { + background-position: -180px 0; + } + + &.eclipse:before { + background-position: -45px -45px; + } + + &.cthulhu:before { + background-position: -90px -45px; + } + + &.three-spears:before { + background-position: 0 -135px; + } + + &.saw:before { + background-position: -180px -90px; + } + + &.music-note:before { + background-position: -90px -90px; + } + + &.concentric-circles:before { + background-position: -180px -45px; + } + + &.sun:before { + background-position: 0 -90px; + } + } +} diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss new file mode 100644 index 00000000..8da58a90 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss @@ -0,0 +1,635 @@ +@use 'mixins'; + +@font-face { + font-family: 'PirateOne'; + src: url('../static/fonts/PirataOne-Gloomhaven.eot'); + src: url('../static/fonts/PirataOne-Gloomhaven.woff2') format('woff2'), url('../static/fonts/PirataOne-Gloomhaven.woff') format('woff'), url('../static/fonts/PirataOne-Gloomhaven.ttf') format('truetype'), url('../static/fonts/PirataOne-Gloomhaven.svg') format('svg'); +} + +:root { + font-size: 1rem; +} + +html { + font-family: 'PirateOne', Nyala, Georgia, serif; + + &, + body { + margin: 0; + padding: 0; + height: 100vh; + width: 100vw; + overflow: hidden; + } + + * { + box-sizing: border-box; + } + + + a { + text-decoration: none; + color: #fff; + transition: 0.5s; + + &:hover { + color: #be514f; + } + } + + .content { + display: flex; + width: 100vw; + flex-direction: column; + height: 100vh; + + .cell-details { + top: 0; + left: -2px; + width: 1px; + height: 1px; + position: absolute; + overflow: hidden; + } + + .header { + position: absolute; + display: flex; + background-image: url('../static/img/plank.webp'); + border-bottom: 1px solid black; + box-shadow: 0 5px 40px 0 black; + background-size: contain; + z-index: 4; + height: 3.4rem; + top: 0; + transition: top 0.2s; + width: 100%; + + .menu { + &:before { + content: ""; + color: #ccc; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; + cursor: pointer; + position: relative; + left: 1rem; + top: 0.3rem; + font-family: serif; + display: block; + width: 45px; + height: 45px; + background-image: url("../static/img/icons.webp"); + background-size: 256px; + background-position: -90px -45px; + filter: invert(100%) drop-shadow(2px 1px 0 black); + transition: 0.2s; + z-index: 5; + } + + nav { + position: absolute; + z-index: 4; + opacity: 0; + visibility: hidden; + transition: 0.3s; + background-image: url('../static/img/plank.webp'); + border: 2px solid #222; + background-size: 190%; + top: 4rem; + left: 1.2rem; + font-size: 1.4rem; + color: #aaa; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; + padding: 1rem; + border-radius: 0.5rem; + + &:after { + content: ''; + border: solid #222; + border-width: 0 3px 3px 0; + display: inline-block; + padding: 0.2rem; + transform: rotate(225deg); + width: 0.3rem; + position: absolute; + left: 0.7rem; + height: 0.3rem; + top: -0.5rem; + background-image: url("../static/img/plank.webp"); + } + + ul { + list-style: none; + padding: 0; + margin: 0; + + li { + cursor: pointer; + margin-bottom: 0.4rem; + position: relative; + padding-right: 3.1rem; + + .shortcut { + font-family: Arial, Helvetica, sans-serif; + position: absolute; + right: -0.9rem; + display: flex; + top: 0; + font-size: 0.7rem; + + .key { + padding: 0.3rem 0.3rem; + display: inline-block; + border: 1px solid black; + margin-right: 0.2rem; + text-align: center; + background-color: rgba(128, 128, 128, 0.5); + color: white; + border-radius: 4px; + transition: 0.2s; + min-width: 1.5rem; + } + } + + a { + color: #aaa; + display: inline-block; + width: 100%; + transition: 0s; + } + + a:hover, + &:hover { + color: #fff; + + .shortcut { + .key { + background-color: rgba(128, 128, 128, 1); + } + } + } + + &.section-end { + &:after { + content: ""; + width: 100%; + background-color: #333; + border-bottom: 1px solid #666; + height: 1px; + display: block; + position: absolute; + bottom: -5px; + } + + margin-bottom: 0.65rem; + } + } + } + } + + &.show { + &:before { + filter: invert(75%) drop-shadow(2px 1px 0 black); + } + + nav { + opacity: 1; + visibility: visible; + } + } + } + + header { + flex: 1; + text-align: center; + align-self: center; + font-size: 2rem; + color: #aaa; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; + position: relative; + + .number { + margin-right: 1rem; + + &:before { + content: '# '; + speak: never; + } + + &:empty { + &:before { + display: none; + } + } + } + } + + .roomCode { + font-size: 1.1rem; + color: #aaa; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; + display: flex; + flex-direction: column; + padding: 0.3rem 2rem 0 0; + + span { + &:last-child { + font-family: Arial, Helvetica, sans-serif; + speak-as: literal-punctuation; + } + } + } + } + + .main { + flex: 1; + position: relative; + overflow: hidden; + display: flex; + margin-top: 3.4rem; + margin-bottom: 4.01rem; + transition: margin-top 0.2s, margin-bottom 0.2s; + + .action-list { + flex-grow: 1; + flex-shrink: 0; + height: 100%; + display: flex; + position: absolute; + overflow: visible; + background-image: url("../static/img/bg.webp"); + box-shadow: 10px 0px 40px 10px rgba(0, 0, 0, 0.75); + z-index: 2; + left: 0; + width: 9.2rem; + transition: left 0.2s; + + .side-toggle { + width: 2.5rem; + height: 3rem; + position: absolute; + top: 50vh; + right: -2.5rem; + bottom: 50vh; + background-image: url('../static/img/plank.webp'); + display: none; + transition: right 0.5s; + + &:before { + content: '>'; + color: white; + display: block; + font-family: serif; + line-height: 2.9rem; + font-size: 1.3rem; + text-align: center; + font-weight: bold; + } + } + + &.show { + .side-toggle { + &:before { + content: '<'; + } + } + } + + .sidebar-wrapper { + z-index: 3; + box-shadow: 25px 0px 25px -5px rgba(0, 0, 0, 0.75); + margin-right: 15px; + width: 85px; + + nav { + width: 110px; + height: 100%; + overflow: hidden; + background-image: url("../static/img/bg.webp"); + background-repeat: repeat; + background-attachment: local; + @include mixins.mask(url('../static/img/page-mask.webp'), alpha, top right); + @include mixins.mask-repeat(repeat-y); + + ul { + list-style: none; + padding: 0 0 0 17px; + margin: 0; + height: 100%; + width: 90px; + overflow: auto; + overflow-x: hidden; + scrollbar-width: thin; + + li { + display: inline-block; + padding: 5px 10px; + transition: all 0.25s; + background-image: url('../static/img/icons.webp'); + font-size: 0; + text-indent: -9999rem; + width: 45px; + height: 45px; + background-size: 256px; + cursor: pointer; + + &:hover { + filter: drop-shadow(0 0 5px #aaa); + } + + &.active { + filter: drop-shadow(0 0 5px #93292e); + } + + &.move-piece { + background-position: -45px -45px; + } + + &.kill-piece { + background-position: -135px 0; + } + + &.loot { + background-position: 0 -45px; + } + + &.move-overlay { + background-position: -180px 0; + } + + &.destroy-overlay { + background-position: -45px 0; + } + + &.reveal-room { + background-position: 0 0; + } + + &.add-piece { + background-position: -90px 0; + } + } + } + } + } + + .new-piece-wrapper { + width: 110px; + margin-left: -100px; + height: 100%; + overflow: hidden; + box-shadow: 50px 0px 40px 10px rgba(0, 0, 0, 0.75); + margin-right: 9px; + transition: 0.5s; + overflow: visible; + + &.show { + margin-left: 10px; + box-shadow: 49px 0px 40px 10px rgba(0, 0, 0, 0.75); + + .new-piece-list { + ul { + overflow: auto; + overflow-x: hidden; + } + } + + &+.side-toggle { + right: -10.1rem; + } + } + + .new-piece-list { + height: 100%; + width: 140px; + @include mixins.mask(url('../static/img/page-mask.webp'), alpha, bottom right); + @include mixins.mask-repeat(repeat-y); + padding-right: 16px; + background-image: url("../static/img/bg.webp"); + background-repeat: repeat; + background-attachment: local; + + ul { + list-style: none; + width: 120px; + padding: 0; + margin: 0; + height: 100%; + overflow: hidden; + overflow-x: hidden; + background-image: url("../static/img/bg.webp"); + background-repeat: repeat; + background-attachment: local; + scrollbar-width: thin; + + li { + display: inline-block; + padding: 5px 10px; + + [draggable] { + transition: opacity 0.2s; + + &.being-dragged { + visibility: visible; + opacity: 0.5; + } + } + } + } + } + } + } + + .board-wrapper { + height: 100%; + width: 100%; + overflow: auto; + background-image: radial-gradient(circle, rgba(241, 236, 232, 0.5) 31%, rgba(156, 124, 108, 0.3) 85%, rgba(81, 64, 30, 0.1) 100%), url("../static/img/bg.webp"); + background-repeat: repeat; + background-attachment: local; + scrollbar-width: thin; + position: relative; + padding: 40px; + + .map-bg { + position: absolute; + top: 0; + right: -175px; + background-image: url('../static/img/compass.webp'); + width: 175px; + height: 254px; + opacity: 0.55; + } + } + + .connectionStatus, + .errorStatus { + position: absolute; + left: 50%; + right: 50%; + width: 27rem; + background-color: #a6192b; + padding: 0.5rem 1rem; + display: flex; + justify-content: space-between; + transform: translate(-50%, 0); + font-size: 1.4rem; + transition: top 0.5s; + top: -3rem; + -webkit-box-shadow: -1px 3px 5px 0px rgba(0, 0, 0, 0.75); + -moz-box-shadow: -1px 3px 5px 0px rgba(0, 0, 0, 0.75); + box-shadow: -1px 3px 5px 0px rgba(0, 0, 0, 0.75); + z-index: 1; + + span { + display: inline-block; + width: 100%; + max-height: 2rem; + text-overflow: ellipsis; + overflow: hidden; + } + + &.show { + top: 0; + } + + &:before, + &:after { + content: ''; + width: 4rem; + height: 2.9rem; + position: absolute; + top: -1rem; + background-color: #a6192b; + z-index: -1; + } + + &:before { + transform: rotate(45deg); + left: -2.4rem; + } + + &:after { + transform: rotate(-45deg); + right: -2.4rem; + } + + a { + font-family: Arial, Helvetica, sans-serif; + font-size: 1rem; + line-height: 1.8rem; + cursor: pointer; + } + } + } + + footer { + font-family: Arial, Helvetica, sans-serif; + display: flex; + align-items: center; + justify-content: space-between; + color: #aaa; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; + font-size: 0.75rem; + background-image: url("../static/img/plank.webp"); + background-size: contain; + border-top: 1px solid black; + box-shadow: 0 -5px 40px 0 black; + z-index: 4; + position: absolute; + bottom: 0; + width: 100%; + height: 4rem; + transition: bottom 0.2s; + + .credits { + display: flex; + flex-direction: column; + padding: 1rem; + + .gloomCopy { + margin-bottom: 0.4rem; + } + } + + .pkg { + padding: 1rem; + display: flex; + ; + flex-wrap: wrap; + justify-content: end; + + .copy-wrapper { + width: 100%; + display: flex; + text-align: right; + align-items: center; + position: relative; + justify-content: flex-end; + margin-bottom: 0.3rem; + + .sponsor { + position: relative; + + .sponsor-button { + height: 35px; + width: 128px; + display: block; + border: none; + transform: scale(.65); + } + } + } + + .version { + width: 100%; + padding-right: 1.7rem; + position: relative; + top: -0.4rem; + text-align: right; + + a { + margin-right: 10.3rem; + } + } + } + } + + &.board-only { + .header { + top: -3.4rem; + + .menu { + &:before { + top: 4rem; + } + + nav { + top: 7.5rem; + } + } + } + + .main { + margin-top: 0; + margin-bottom: 0; + + .action-list { + left: - 9.2rem; + + .new-piece-wrapper { + display: none; + } + } + + .board-wrapper { + margin-left: 0; + } + } + + footer { + bottom: -4rem; + } + } + } +} diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_mixins.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_mixins.scss new file mode 100644 index 00000000..9b7fb2d0 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_mixins.scss @@ -0,0 +1,26 @@ +@mixin mask($url, $type: null, $position: null, $size: null) { + @if ($url) { + -webkit-mask-image: $url; + mask-image: $url; + } + + @if ($type) { + -webkit-mask-type: $type; + mask-type: $type; + } + + @if ($position) { + -webkit-mask-position: $position; + mask-position: $position; + } + + @if ($size) { + -webkit-mask-size: $size; + mask-size: $size; + } +} + +@mixin mask-repeat($repeat) { + -webkit-mask-repeat: $repeat; + mask-repeat: $repeat; +} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_modal.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_modal.scss new file mode 100644 index 00000000..49dee43e --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_modal.scss @@ -0,0 +1,214 @@ +.overlay-dialog { + position: fixed; + top: 0; + left: 0; + background-color: rgba(0, 0, 0, 0.5); + width: 100vw; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; + z-index: 100; + opacity: 0; + animation-duration: 0.5s; + animation-name: fadeIn; + animation-fill-mode: both; + + .dialog { + padding: 45px; + color: #aaa; + text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; + border-image: url('../static/img/border.webp') 0 fill; + background-color: transparent; + border-style: solid; + transform: scaleX(0); + animation-delay: 0.55s; + animation-duration: 0.5s; + animation-name: unroll; + animation-fill-mode: both; + letter-spacing: 0.1rem; + min-width: 20rem; + + .scenario-form { + input[type="number"] { + text-align: center; + } + + .file-choose { + flex-direction: column; + align-items: flex-start; + + button { + width: 100px; + } + + span { + order: -1; + margin: 0.5rem 0; + } + } + } + + .client-form { + .split-input { + input { + max-width: 5.6rem; + text-align: center; + speak-as: spell-out; + } + + span { + margin: 0 0.95rem; + font-size: 1.2rem; + font-weight: bold; + } + } + } + + .character-form { + display: flex; + width: 75vw; + max-width: 810px; + flex-wrap: wrap; + padding: 1rem 5.3rem; + + .input-wrapper { + label { + font-size: 0; + text-indent: -99999em; + width: 90px; + height: 90px; + background-image: url('../static/img/characters/icons.webp'); + background-size: 512px; + filter: contrast(0%) brightness(70%); + transition: filter 0.25s, transform 0.15s; + position: relative; + cursor: pointer; + + &.brute { + background-position: -180px 1px; + } + + &.tinkerer { + background-position: -90px -180px; + } + + &.scoundrel { + background-position: -270px -180px; + } + + &.cragheart { + background-position: -90px -270px; + } + + &.mindthief { + background-position: 0 -90px; + } + + &.spellweaver { + background-position: -270px -90px; + } + + &.diviner { + background-position: -180px -270px; + } + + &.phoenix-face { + background-position: 0 0; + } + + &.lightning-bolt { + background-position: -90px 0; + } + + &.angry-face { + background-position: -270px 0; + } + + &.triforce { + background-position: -360px 0; + } + + &.eclipse { + background-position: -90px -90px; + } + + &.cthulhu { + background-position: -180px -90px; + } + + &.three-spears { + background-position: 0 -269px; + } + + &.saw { + background-position: -360px -180px; + } + + &.music-note { + background-position: -180px -180px; + } + + &.concentric-circles { + background-position: -360px -90px; + } + + &.sun { + background-position: 0 -179px; + } + + &.envelope-x { + background-position: -270px -270px; + } + + &.selected { + filter: contrast(100%) brightness(100%) drop-shadow(1px 1px black); + } + + &:hover { + transform: scale(1.1); + } + + input[type="checkbox"] { + visibility: hidden; + } + } + } + + .button-wrapper { + width: 100%; + flex-shrink: 0; + } + } + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes unroll { + from { + transform: scaleX(0); + } + + to { + transform: scaleX(1); + } +} + +@keyframes popIn { + from { + transform: scale(0); + } + + to { + transform: scale(1); + } +} diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss new file mode 100644 index 00000000..9293874f --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss @@ -0,0 +1,328 @@ +@media // Extra small devices (portrait phones, less than 576px) + +(max-width: 575px), +// Small devices (landscape phones, 576px and up) +(max-width: 767px) { + :root { + font-size: 0.9rem; + } + + html { + i { + &.icon { + height: 5.4rem; + + &:before { + transform: scale(0.75); + top: 1rem; + } + + &.brute:before { + top: 0.9rem; + } + } + } + + .content { + .header { + header { + font-size: 1.5rem; + + .title { + input { + width: 50%; + } + } + } + + .roomCode { + display: none; + } + + .menu { + nav { + ul { + li { + .shortcut { + display: none; + } + } + } + } + } + } + + .main { + margin-bottom: 0; + + .action-list { + .side-toggle { + display: block; + } + + .new-piece-wrapper { + .new-piece-list { + ul { + li { + transform: scale(0.8); + transform-origin: top; + + :first-child { + margin-top: 1rem; + } + + &:not(:first-child) { + margin: -1.3rem 0; + } + + .summons { + span { + line-height: 3.5rem; + } + } + } + } + } + } + } + + .board-wrapper { + margin-left: 0; + + .map-bg { + display: none; + } + + .mapTiles, + .board { + transform: scale(0.8); + transform-origin: top; + } + } + + .action-list.show { + &+.board-wrapper { + margin-left: 9.2rem; + } + } + + .connectionStatus { + width: 75vw; + font-size: 1rem; + height: 3rem; + + a { + line-height: 1.2rem; + } + } + } + + .context-menu { + + &, + li ul { + width: 110%; + height: 110%; + position: absolute; + top: -5% !important; + left: -5% !important; + padding: 2.8em 2em; + font-size: 1.5em; + transition: 0.25s left, 0.25s opacity; + z-index: 2; + } + + li.has-sub-menu { + position: initial; + + ul { + left: 95% !important; + padding: 3.8em 2em; + font-size: 1em; + overflow: auto; + + &.open { + visibility: visible; + } + } + } + + &.sub-menu-open { + left: -110% !important + } + + .cancel { + display: block; + } + } + + footer { + display: none; + } + + &.scenario-creator { + .main { + .board-wrapper { + margin-left: 8rem; + } + } + } + } + + .tutorial { + display: none; + } + + .overlay-dialog { + .dialog { + border: none; + width: 100vw; + height: 100vh; + background-image: radial-gradient(circle, rgba(241, 236, 232, 0.3) 31%, rgba(156, 124, 108, 0.4) 85%, rgba(81, 64, 30, 0.3) 100%), url("../static/img/bg.webp"); + display: flex; + align-items: center; + overflow-x: scroll; + padding: 1.2rem; + + &>div { + width: 100%; + } + + .character-form { + width: 100%; + padding: 0; + justify-content: center; + + .button-wrapper { + width: 100%; + } + } + } + } + } +} + + +// Medium devices (tablets, 768px and up) +@media (max-width: 991px) {} + +// 4k+ +@media (min-width: 2800px) { + :root { + font-size: 1.5rem; + } + + html { + i { + &.icon { + height: 2.6rem; + + &:before { + top: 0.2rem; + } + + &.brute:before { + top: 0.1rem; + } + } + } + + .content { + .header { + .menu { + &:before { + transform: scale(1.5); + transform-origin: top; + } + } + } + + .main { + .board-wrapper { + padding-left: 8rem; + transform: scale(1.25); + transform-origin: top left; + + .overlay { + &.token { + line-height: 1.5rem; + } + } + } + } + + footer { + .pkg { + .copy-wrapper { + .sponsor { + .sponsor-button { + transform: scale(0.85); + } + } + } + + .version { + a { + margin-right: 7.6rem; + } + } + } + } + + &.scenario-creator { + .main { + .action-list { + width: 10.2rem; + transform: scale(1.25); + transform-origin: top left; + padding-bottom: 16rem; + + section { + ul { + li { + padding: 0.2rem 2.2rem; + } + } + } + } + } + } + } + + .summons { + span { + font-size: 0.75rem; + } + } + + .monster { + span { + font-size: 0.75rem; + } + } + + .tutorial { + &.step-2 { + top: 4rem; + } + } + + .input-wrapper { + label { + &.checkbox { + &::after { + top: 0.3rem; + right: 0.2rem; + } + } + + input { + &[type="color"] { + width: 1.3rem; + height: 1.3rem; + } + } + } + } + } +} diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tooltip.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tooltip.scss new file mode 100644 index 00000000..fd88d447 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tooltip.scss @@ -0,0 +1,44 @@ +html { + .tooltip-wrapper { + position: absolute; + z-index: 2; + color: white; + background-color: rgba(0, 0, 0); + padding: 0.4rem; + margin-left: 1rem; + letter-spacing: 0.12rem; + transition: all 0.2s; + opacity: 0; + animation-duration: 0.5s; + animation-name: tooltipIn; + animation-fill-mode: both; + animation-delay: 0.75s; + + &:after { + width: 0.75rem; + height: 0.75rem; + content: ''; + display: block; + position: absolute; + left: -0.35rem; + transform: rotate(45deg); + z-index: 1; + background-color: rgba(0, 0, 0); + top: 0.7rem; + } + + .tooltip-text { + padding-left: 0.5rem; + } + } +} + +@keyframes tooltipIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tutorial.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tutorial.scss new file mode 100644 index 00000000..13671923 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tutorial.scss @@ -0,0 +1,33 @@ +.tutorial { + font-family: Arial, Helvetica, sans-serif; + position: absolute; + max-width: 36rem; + background: radial-gradient(circle, rgba(241, 236, 232, 0.5) 31%, rgba(156, 124, 108, 0.3) 85%, rgba(81, 64, 30, 0.1) 100%), url("../static/img/bg.webp"); + z-index: 2; + padding: 1rem; + border: 3px solid #452e27; + box-shadow: 0 -5px 40px 0 black; + text-shadow: initial; + color: black; + font-size: 1rem; + transition: all 1s; + + &.step-0 { + top: 25%; + left: 25%; + } + + &.step-1 { + right: 1rem; + top: 3.5rem; + } + + &.step-2 { + left: 0.5rem; + } + + .footer { + margin-top: 1rem; + justify-content: end; + } +} diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/main.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/main.scss new file mode 100644 index 00000000..e5af479a --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/main.scss @@ -0,0 +1,9 @@ +@use 'layout'; +@use 'form'; +@use 'modal'; +@use 'context-menu'; +@use 'tooltip'; +@use 'tutorial'; +@use 'creator'; +@use 'icons'; +@use 'screens'; diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/accordian-banner.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/accordian-banner.webp new file mode 100644 index 0000000000000000000000000000000000000000..cf234912f63414b2c020c31a51cd8af54caf4dd1 GIT binary patch literal 1246 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%0D>nOZ=rz-@nK#Ex{-JI_|5GVc@%^}e; z2WSp#?N2>%UxMTcBDKo8GA>l9!pi9b2!xp~Ukfj9m8i?X7G=&9&v@_n7yQV%`gs2p zjE9W=TxauAsVlP#PN=H{F^hr!8SFlzxMA_MU5fMut~9KTkfO3Ue~;yO*Agv#dG6sQ zwl*#BR35)L)fQV~`!5@WBX-J6(A-{KoL$p4c-yN50%YVNJ&*N4XN>Ea~U>$4ww`L8cH!i z4MsG@Dj%i8NsTMcm*Uk73V|$ZginIT28N$QUo8@~Lo1|K0S?SOe!<@fO2PqCM*lFg z#XtuLnk3gVzgO=#7?x>T`U)i8tH9cu5ij(@WNM<_EN;aozo!YzBPGN@a)83o84FXj zQejC}&q&;=<4_3*9#=Z+`!vBBXqt7=?#U4_jPzga1XeRPma*XUtQ%W;oXlaz$kp^W zwEtoBVSpsxAyqq5U4PBJ-N;DQ;=@e(62H1 zcVZS-JlG(7*H6fRW#pD*GM*dQYRp4hAsC*?{}`w(LsXz!uZTv}5xaQOa6H@R?FiC{ zCE0DD(|VY9*h}!x8IDB15kx3RSVI74mBBxVLVq}J_Wx*pOm$XONuzp8X&zX;(^oLK zwnS?Yuf>oK!?CH7Y_UNw;LQ3BezlE#XW4Af#c<=Pt0(pyV0MDvb7J;+Um%J1#UT`c z3Wc|+KmJ#0zMjO%C90D$KQD&hP$jpJCSW22} z#`f2rL|nhiS+kzp?4B|$C+jSo`qPV(R*j;2+Rg96A4swfbKQULr|f#Q-oiPjXXi); zPiaKs=Hd}tAV73xcQhcK&Tb1&3fySD#n{$QL;9mWM@^LU8GZmKiCBESFt7!kZ0BjY z&V{>V^Eim$u!LABDQpWL4F-_ce%=uMg4|G1WS>fK;j|=s88P|a{$PIJo8 zsv8oq>=u??-@8H$1ihJ)Y)f%f{inNGjr%rt&Cb~DYhL)W#e(GZE0zW!%utd|Z{uOce12X< zN*c54umEC28vVWaSevZ@oq_^54zqW(80-{2>D1gC!ak;)p2Z%9A6BxYmAbXfT|D6@ zx=U>$b#2Vz^*NV^R&HFy^qffjS^U7eeny(8BdvXMDq+mFNd8-Zs67giMM)p+iA%7~ zfuTS0cc!Sg>$&$@VB6A_77RrmkQf}mkbKk^j|il|X5r*N%^pH}=>k3!|T zXQLlRLSTyA>XyY~C9gi%7#P|apSSZ5={SNstv>ESg!-t5J3!v@hgF#K#QeDbD~*bN zwLqNT!X%XPu-~m2s?R6=r#@5{^Be#?>~@YqBlwV29pU%d;21Q{7JQgN0zei871ENT z+Ea}E!a~sTtaTP)wUN?`Z|ic@-}ElJ*9~s00LawMnDZ<6mJg=2H7%`9h?a({ZIvxM z^z-7vk{uM6rhWj&3{qnLb$uB69S&0^wt@oYdW+vC@sfC-c~mGaXswn3Z$EyK0f+yK zh1=`1uofl=rI%YmcbID9o)KaoI2s?j2JJf{-fQGI(!>E`g9qX_DH)c7$D+e?8Un=lBy8;jBRrai9uAoaTm2z78ObwyDt)kPT zIxMy&*&Icmy~SZT(YAgNKceJFJ@kB+LEMuog}KH2zCC;q;7B`XLIG^Nt+d3LGS#lV zk5TsMf^_HiCGO)R?P6U*T!p#GMGpomm$Ap`=cAxD!zeIaN6GG^g&)VuLv>-0K9wzp z8fKrtRI?fiGjY7Hsi|aSXF?Z`;H|LEqzHCvkbiYH6=}IC%Cuf(;r0V@~lfG8;S?bx^r zagX`-Y&exXrpzlf?(|GA@X!p4S&>KOi`z=I27WAxb;d}YIrOrmhAnJ{)PtQ+pT9{> zsBQq0n*RpPB3;>t)4R(wAK@T$%9&_m?gqfN63jBm%>>TnZU$S77-GCQ$}J}^EA|0@ z9YX_L78#oo;9Ty^vN)&&I`qH^{!bO=xuqMZgn15$<)H1ESI<0^i)Rxoua=g(2Xiof5v91RHZqc(_vLN17%__v8P#c}pa6&x|3+O(r&Y3$gh zA@E8|`GN0MA*^!(9&H-hQ9F@uc$*X_2Iy4Cx84X*&iz*Cmu_bvv_?CfVF3}aPZ@Z) zDQFZt06f7&Mk$)M6W_+U5E=%K8tKU#PU?faP>s+$aYV{H@VUGG*#Vru6 zQ*j6r#1-7EirF=WB}#a^e=im6yUJpgd@sP#xyyGP&7N>$acTV4+EV^c{?cxV&!ciHyFZfNj;6``6j!IG1)AUiIGy_tO6T^2Sllz=h18I$LW@&ylY_7=?)y&K zpq%5Y{1ma1u;~<}Lww z=glB@g;RfoI8zgTqJw6vVdgYG%t>RYG+1Cw`P~bfRvSLC$)%cv+IkM}8u!3`w=v-B zL5=I^UY=m#0Eyx_QolLwZ`*6iY#rj!9kOr`&s+szHIgt?E=UucZlnr0z_67 zKwLcgf5ay9XV$0)6 ztF4;6c7Jfn(dhO@$bj-b&Z^2e;y{l8;m<{q(WlV~d3@}}bOx{0=TB7sFc$eHu;5Dv zatiLadvQhx#2XTC9&$S!0lA=O%$FEdscU}Iw{z``w-0kdCA3hFFaR=?KY%ITz?Jg_ z2u8$va^9-Tov<^eR`Aqbg+^lGFf@SWb<=54d-dDpl+jd6(MvJTE!?4REVmVo$2dkL zlz&-jZ4ns8n$`~sJ^s#}3xz?SH|AR%PL)u0kWYLUs@w7uxw<#}F(eiw=uEasBX=Oq+K7lzaCZ3!6aO3g{Pp6t@*)> zpH7Nw8xT>{B4zaBU* z@Al+Z?hAGBRhE%<*;@Q#vIbW>!wUN@4!D7J2N{!AbiEePQw108ATg+@h@q0LzpR%Lx`WQFqAG8V;6NhnBZPY!|q zeQ%7OT`O8qLI|y^zi-_!w!nDg!SdjsOb{iGWe{wf+$k*(hhObG_)hCH*T(W;91P-M z?p}yX&MK89IB*M;vLCYPa8z7LL1*&eU)yGh0v9c^M$97W6qwl+EuE3XgrgqT^Vo59 z$6B)yRw9LbrRO@*eklYp)T%Q_5`#D^HmPpGZxziDP&82I4)=&c|#mQv@FHSlMt zPo`Z_Tv#Z!7TDYY_szMJ`@)>dnT1_=_?ZpyojCCfrye-Gc* zJ=wCHTfxTlfOu4IW*(vvkD93&;qZ-c!6imF9t;)mJYJMSB%<{g!lh3|Hy(u%t--*+ zM>NeISZVko`aQ(HP2eeSo;Mw#)^G6&hFKJGs9_<2+|6P#c8J8LqJXoKzwXz-CERDj zSKH|yMHeaicG&BnPvw({sIMXgJz+lUoAqgFl1BI@HIC01&uT>R8G=YeWgv!Rx_uW- zrybXwGbL(@k#D6oukQ)CHX&Qz@eMD|0Z^8Sn5XCad{1Hu?P;R?qsbqjcn$2bQK_BQ zI{==nFG)Ryfp%(+=wkGB?M}d; z^9voFgp#zgI2(t));k_dwYnzvk?ESmSX91L)O!<y@<|JdiIfD?6t8TNlb~oC3RQA6EamLO@3Lg7}}Ra!h(yq`cKL6pav=G@Lg)> zS#3N(kjl#sAneC&MS~%Z1UWo1=tkKz8L9lUJC!v`pA`2VxLwh0i*zc=Ikg?u4PjF7 zA~wlqai`Z=Ewyl%GKFzf-@mxhHjL6O8L&;KV|_&-NKk%ssr|?oMykFq@H1nf5?E75G zAoiYN-xfFp&S3s8?lGusqQ!xs1`!j!L8~Wn`faYN1r?MMyxt-Wj={DYYCB_deY*m$ zm~g8PxU6Ht7W>O3EOp;9XI5%Q3CF){8^e9kq~B!}l`(4b75uaEf5wTwY;Uafk}pf8 z2U1j+n}BoH+v2o7c@z3L<78~r!MWWY^0oSZO^M+U%`y6}j;%4|sFddOszhL1Kz(=f# z0spwz4(TFu!j4-(Rn+-8)E@vU904wYUN|m&Vp_w%wx_zb9Ri{*mNM-$^gP9Pzkab* z8N4&0Nw0yLrMMI4M4FKY?%~e1fS%-ezapnnR(=9kP{WlZH^fT+A`tLx51z0Z%-ld|e8RDK8IgcUdqCt|~iW&qJ8-aG*#E%5{^WHcMuVq!CVBKeYzD)`DG z&`T{ug?B5CtO}ovQM|yld!yoYB{^@ZuhEA_;2?T~jzvL8K51mJ_HqU{!H>^OSE)0y zkC!u57?#>KNjwvEz~fd0HA@UHXD;iy8sbj)eQc}hPaKiq;7+X0&r_h`gYfM~JK@-P zz)>9us5rbw9~f4L6}k%&Y5?miTf?NH$SEK3H!Tz`QWTa}{E&YVaWJiee4#8XIB9?a zGEgvmy|F{eDo4S@EoAU-qx}3yjB`>>tF)=a@Kf&Pniw0$_6-#g8;7MiAue_FVwGEX zxfz7ZEiMfYlX?mpgVv({ppg#M(Tu(N8ob>rM4S|L+TrXbEVf|dKm02DbZ$ZyGHgTg z6WqO&5Aakcmyek4@;JMs2rz}ed&`-!BN9hr&t}EaGNVmy=Q-dw*$cW_JHUA88 z&Dm5rC?s(TvOSCdSIXNs!53{zJ

92SVDz6i(aqT9d+Z^&udgo)I$HZ!WExFUrCrd^>n z4kN-XJf0&JdCqt4H1 zn-qAuEJ%5Z4?tv50uPD+4kuSewTFlGOiHWZ>zSIe(F{F@38qZ~vrGPb-2&3yaUQ;z zPhUy%zUGn^G?*ZUaA{HYxys#bWp9E7!ncpdz3%=G2N6yvGHD!g3^HZ;8?8nnJ$a|3 zEB5n>Se+n_n0waPHeDxk;AM$lgN28PAd1uK1r_rAep7zqlckhpgx|HsuQc#G$)phX zfhk&3oo7G&_N89Qa2@jm6!}++pJf?BG!r8drYAC}9g7}{1X8HK#kt5KI?H1P#AY0+ zvVhSHYO-bnSwTX`QS#qdso}{p0#F6c##@;B{9_!`+)}Jhs3#dhxLAIVGK8{HQ#T^^ z4jj7HahlCdzpd7V^R2PiL$h6FFp1fJ(C7ZpYj$_4F2E+Q_$Yq58q2CB!?H$L-s*~ugPM#FW8SQjS4P}scRF6j7<6hGs>{|Iz@6&wt2{y+m)E_~Lm2V>vmaf?L zfmmo|N;=_N6Oqg!&+8$RVQ{no-T5eLWn9dfYdkUx`_>YRk%GFAQWTeqH8uO}L>3AB7iIq>q0;Qz3C zmwa;Vtm%PhoD&1&l69oB-+KYhNdog;@9V@ST;<>tt7>-eVY%jz{S#swcN#&-QVQVv){2{-L}21V(~^#AmUiRt>oa=l_DzupS zN2~&i_wv4j36Eb&hHV3iB@!8xHq7O!b|G8 zF8&-F47HF`GJc;10j)syn+>!JQ(HF>&DBvQG*~$rZHcvO&~;e&fruZbJQLNglBP9= zBW&UJDO6Rnb!kn0^arbL%cL27au|1+C5HF-rg)O<7Y@~-G5{YNe&R3HrF>ic-#!Yb z*{PXGp7!E-A`EQX{JI&~9hUX&GgU~V4p!&{E-j`5>9%Wl5_y!MkufGdKbw3l%^^~n zX?13@=?R}d0TY|U(e2OpPIG^cv8@{)MYe={yn>~%+PLo((*P z1LfD|&A$d1yB>-jo)R}6(CyzVac{0sNS~X3j^lglm1}dWmtkgsUr1I*&^KyGUIvW$VpR_7RSGgwkcYty9kOnt3%L3ibjCSHr;*^`% zZW5`dE8g6#waH}t@}Og#wTD4ds3;<_Zq1Q{U=WH`DE}NQAP+jk#+J%7v5}bO9gJn{ zyR8=c7N4?Bc^qE@eOfpvrcW?}jNbMwF|IuhgB=OLO2&7mM$^M#=_afM9rCysU;%?l zPY&xx)SQ^6G1yCV9xw2y39W%Xw`L@+Qis0#U6iAn>z@ln(g{+fqG2k@SEY&gL`MynxqX=_{%#Nfs38w3kYeqe4!3w1M4;Ky7R9|2C?lK8vwZi?uRH zAwh5~MicU6{P9m+vlv}$vw?$3QJArC#R^B!a`X>q3zEIN!@9XlFf*Kt;kxuOs>;Hn zOK|itT)eun({uyr+>Zik^4JbnH`oTaZ`Nq3@=9H2D;al}V?Mn3Q!(4RT<_;UC53;U+=4+a*)UlwkS`u~RPBQ2R z?Y>+L&zbOv`$FtQdDO=fj>a9>BWT2PkROUcF*`Lt0#0iP;YNAvSWxe~kQ?$q2;-)z zW;7ZfZ@Nv7r*XOd=41k`gM^D1Bv{jywfcTO>JT@7WV3C)qQ0EPkA>2_3({no1u(t; zrV4hu?y@;qT4)DbFtJj@NLeW0p{sgqAuWK+iB#H70r3a)-vEY(@IXmC2s0H*nID}- z+%CPEy}RA^pTLVqos~fxKbeNEjd_Tx5P{ZAYp*M^(VH=#T6o`tf6A#(Sl65l88FW! zEh*+dfLRZJZGXhQq^MyH_LBsb@tDqPLktFLC^~!cm7Z5+B7Gc9?f7$?3k9Jakk#19 zN;Rh?gKGD&QZ@h2Tqe7L=pCyo+ZK|QJwA_SAUaJxW-rv$;)0oxBGzY@q98|ij^Dw8 zLjTG9II|kGwc?VchNpL>4G;WAAo{(R@0rX@T?&zZM{D?NjIlL_eN)|Zp{K#5gdy-0 zBq0|}P!+}19jG_rdwh#;+vdDc+#=NH)qB+#?miD2*lR^Zs@w2JsN$kD6Uq%HkA;KB z_l*Vr9H7{a>7pxBf_P{Yg`OP^~IN3v2PztpSPKOSGA5e%S#BR zYlQ!a+HDcQ0n+Q6IU^P|&BF98pV(LvY&~Nz&k>Xa;WtaS(kb&qN6~aOw^4Q&aqHJ$7_qH?e~6_&}-OxtiRka?s{-cnjzjE}Jqc;WKnp z*^3|oUv%h-ixgEDcwG4oFE{r@9Rz(%dnQQ+oKhxYXOD!qeV7UbtASfwk$VD5o`RXI zZVBBdn2cp9*a&8@2YM1#b)vJmP6ZgDjQKIVR6 zisi~70Zi{E&iOPgQPQmeKvqTr*QnzB^8)D5by98<0=d&UB2{I>k{y}&DRyRm+&*@) z^vk-u+=GDDdnca?rIi--6O^qQD_Vd)b{^|`0F#90BZ;E&rJD#j`^vEeq<0#?uEZJ} zl{UdHuJ1L!F6%tki0_BOLmw7{=K_sm%!8L;hII%NAFK}|*_b~^Sq}=dTr>7gpKj$SWp*;^lWMl5!YFyBdt zPOPX#^&&eKibM5nXV{0j3g8c_9ljLvy8e%=1Q8@YlRyEOhN?Jbg0qS!+EZRKTN?^5 z-J0T~2?s5791yK}hckC1qm_H$kn%Xx*C?Ab0RM}k18K)wn~@7^Ss3PKd%muYKA#p3 zV|K6gAAeHAOhgdn3hHUG&{p|3i7MXkA${w;Q@Pdw8(HGl{i?7kLtpW^9ul}!?AZfK z>w?+TaA9Jh_^_NE7MSI2w=RONoaS)(?Xch64sJqJH4qHgasrW1p3G~ROyUL5)5(q6b%z4Hoy$SPAr=*;3L zzTwnw)cza}{Db{x7M%<}o=u*@3}-l@!DqS+gs2R~MoS!nse}i#mM;zA0DLhRQZ-Lp z49FLx@}Nf^o27Vl3Z|Domt3HQ)44b;L%8E7oa4^;6TN-d+)FJ0;;7eR7;3`LEnVhE zRUv9Fz74`Vw_KO;yg#0WLRkKTg||(Ofw)`)ay?#0bx;v_#`;8RlPLjDStW)mO}5@Q z#5e!`^>#xoH@rkRnre0F749LZwrqbhF03S?+Kqb<+SHPH+%C`-!*Z5NBMCafb~+f? zDsDc?<{9PpSj>IVc(w<$0$jHsthuFvsX2teC~0Od60#mQeog$=?01zj* z17)Qe{vuLaN%wIreGnHSf0nM7zv+5>cJ|tkdlx(1In1t}9m}DJOWswbAwB(yR)_#-rU#0G2Dyxoa98@;GwQio>Nj#*ql+EuDQ z$JlO+5JR!;#(j3F(%vdz@=IeDX2!wsxh`OBP@Ma=DdP(FJ4i=~@Tz|fwe&}F{`JR9 z?DS77X!xx9aptte?+`4{O0bYoXKTrkI`23;jbh5SCrv$Jqr(lT+A*OcHdwl7uklD- z7)ov<&mO%mFLXJ9DUgkM^RhHAHSmLc83Q1wL;%ORLjsF~toH&DPXNC{g2w91Bpqqp z7+`dd-n+54a3g^2_Ke^YV~GBus(sHj{i#cMV+v4A>qKXKa=t%2tbgNl^wlX*EPEp! z$T`8q<Iz>?rgek-sTTA1_7e2HS!GY%2mc9vx;6C3rMa1`B1=IRoi zM`A~}K6Da+XR2GDVG{omEnG#XrR|fZh;6p+a=>$UeG$E&*z zVVu?@b=u3eECFaz1}N+R(#EWFlz5ID6E)3P-(%vkEOZSuxZB0|r9%)c$BP7vxCq^& zln2*Qyj?3mLfIu*`9`ahA=!C2GU-a`NEolNzTp~+ew1;n%$7U8dMH=5hb~-DF5dBF z+%*585dq!xw(!6N0R#+eq;LEk(^~IA;n~lg=ZA544rSd2JN=)>{hgiZirnej{z%h! zwfDe3Ud#OS-9n?9Vij`DiQXedo*rrlj+HVH9=guIsX`#FLPxVU+2dsyH@T(Ts}Tv#84MMFW`)h zB7dwZSfhE(F(&96Tm6od^WqsASfzQx_EV52Ev;*P)gZLxnw88C@H+m;eABUII&fNg|C3?vjNq%u-k3?hIcre@+7ZEBcAwx*}#Vz)KKNpG(+8F!-2Pvy`i0c=ikbExm zhOyfb`|%d_3m#-{7C7e=V){XZ;!dMQfYaH)q0mSPnZw4Sxud>B_mii%Wn&oUijI!! z@=+Yl8&ID!lLBFD@5y#+To&uNa+MAIE`6AQhnvIAjN(E9rhm->%@WbTOI38P^!onh zz-F;8H$mP(+w^2waW8ajoFa+oWMZ%)paZ*c8G{iqAOyV{0qA_ZoHD0AH_Znx6oG}qMT$b@<1UqVey|}t$nSP%jePX!^I?d19zDVWJa|oA zA%rK=Nyi^!P|04^)1PyCI?=ML5-!CVs7D0NFF@sSpM&SQq#-r+M~N` zcik-zkeXg#?9I0sW7+9s(|(qwMx)A=hxn$n)SK@W!5t}_c)I+uoBsiN`i6K52Ar8n zr$Fk{f7y=$Ji8#pd=6F&jLQmbGuCu8c=eRMauU-+tdvMxLovjtgEw_5p_%he)+-5Ch#atY=V z{oCAyhwM3L7g6V+jFK|(!pmSb?O2%TCmEp(t~Y>Avy)Fc+iX=s8v#BW?cHHQv2M*C z=p@e;-ZJ^E=weOUSRV0yT%jHR@OJF@09{vdv+{wDU}*g1L>0|*g7kK(7$ZBQK# zRV(lnxV8;BHVHiIBlL8Bbzu&Ec|_@Y#;&n?gOSURymzP-Ij|_H?6cMx3%IfBx)!EW zXnE&!^DcpDkwn9NZ9=S`JzGso;w#R>?gy5~2zWOA$ao;VZl*}%BMR8e)oY>ewP`(t zZ1C+_UFld1&Bt#L$cJ+6Hn~1F+2v-1e=&aA)u~1$wj>j*TL*HC`+g`rzwqR5%Zdg; zLn`MRjqw^hbH^@V2bqq{;jAyiFv9Oh#3m=$b|d|BehGF8ZMu&bk>$#MPNwnr z$(5CJ6!yywBBj8bub2w46DCoQXK@C=Ya;nQEZ(~dHfcY+=I%Xtx(}3llbh0y;#F|w z93-V5)F*sO12tNj6;xhybXFNroAg4g2e!5;?z6MM!48raZhdlKGx;W$!{u8Wv9l9k zhQ~r)$$R+mSfGJcct3#(X^%d*hzbBQkjERpvQedS75a6g5r9r`o_3W%AmNBx#>%JB zh&;-+s&38zowE;I?eG$S{V;9ihg!7K10q$LNb=m;{k5u^4IJ}=rVKg(3-rLka`|rE z1**g5`xJmG`)SR=jz66=-V5)ugv7a<$eS4(>-eyq9yrff8=Gl25yiS>3)#UwYC#~%nlrF37~n%y@O7EEqnt-$HnY2?r~tQ_qRdTIT(O1{!j zH??MS=2MdQ*~HidT^2i4r*}DTI&?e<@BZ6aAd=(JhY6&eOv7moaO3dkV8zSM#X_-X ze~6S!h}>Ch%&13PFOX`z++meWH=J2|cbh{#)Yh%ZdDUDYy(iNHILZuQa;~|U$~)~eq9Nk&|8h^zGjJ`XR~nl9V(e3j zg)X!h8LQmTqBVop@Wb76oGri;0sc@>n|QCRBp(`04%#_&I;tyb;Kis zFTVcAm#1L9Xi8wUb>4Gr7qQN=V(G;@IBC<}_c*OjCP_Y*6l?z6-JxTx;Qkk4J??NV z8;U&7TI}{g zaU7CzWs}`JNMC%4oKE=R;s*?%x-UvtvoX8+ka(N!E$Uj7aTZ{`!v!p3X81Ul$)-#!nV+&2X3$R!-lzg|pHY(!})2&BeAxT6MOqDx6z2 zX%j7>XQuLy*LmVXVGRUkb}KdbP}%Qgfn8Rv&3oqj##|`e7KB=KGyZRuU0v0_{MNgsis}Hr;M6<&7^f?Jx{>eLg zzgkUYh5%G3Yw4f;GFJg_>Tvy(8Ys%Q9wdQD?u3`(^=G!cv3fc&@O?yOaI|JK2TMAw z092FaNB{j-bKl05;SW=#(>J$l&oEf|s>XW`3siJq(}($Sy6_A5)B@F(!<}!3gO0of z%~m>ciB{>2b?d#eb@h1a5-(!ADoicD_=eQIetunp3P+S)$~{XISCWEIKc@R^j~8iz z*leSIT;>y)G~>)A*;>e%b&kSM)@}AZ_4>2K@MVMBvm*H8C9x{WWTri~%1nHJ%rNvh zg^cXBcK}xM>*kDxosHc4g~xydsUM96*GpF6StI7(d!q-ToO^kfQURThC-y-jf^<#S zU^_#WCq{LyB#MJz$6fe9AHXd72?6};!~T zzz1Tt2WK(C8lHNNXez4Ytu#4t$#P5y-q^2;UqoneVsdr>blaG>jDssg)^(^*MqdyV zG$2&LpSI8P!rU<$b|GBKQu~d#1u>3vac_-rTAp#C^aR8^TndmM%Dkz3S~Ow8ct)iw z1sEsp^!=EK8X&7Qx(kF2qvw+!V{49flA!K+^LGxe`qSm;-T0`HZkU<=1aSv9O}`IJ z-5U55j#X$A7$sh^^jC8dxNQWZ)-0)Rgpb_j!4U|XJgt%G#tFqY)HEg5TSorBWP~+g zh5p`j$D;nnxoPusSi$IiL2MhutpyDrHCC@>m_emuyix-LxB5f}qaULmmTaJD@mBD!3}k5dZoxv}k@?fuoMG5ai7z$JS^AQB0y3 z=Q@25(~ps}HPaWCNRGh~CDbN8&S(9saa?5lzgtn<8)HVhr0!H5mQO87Pqd_LEIpxE zMmxN=dgq$jFb0kt<8+Be=WIV6FVxpIzGdqZw{mg<>%~Fhiv1kezN|Uu+3?Znv-Opq zBDqMKl0(VU7FQ4FQLQ0KsX5~+Szv*o=EOOuQ@-#Io%<_@Mz9H-;xv#UL@118m=#l@ z)L3+K{8OI)&84UlO0=0C0DQuz`=8QoJxIxP0!5u`YKO+1%V3bs3;kP{OWDgJSU?6Q zd}AmGN)NnQqBKMvS^WkwIT`i-60wmpyeuS~f;P%b^{H^`x@C48KeaJXjntX~2lG9A z2GqvN?T{_WljJQxGF=H1rk7BQ0Jg%LkJMH2H}@pE^Qq^&#CK1s;y*bT^4?f#pxz zT#gqZJ*3{FQY@SAI#X-uA~NjaaKI=k()5kISQFnv0jeSBjTUX{7-4Zh$=S<6!& zZ0DGbk7}-Xk!yPY({Wi857SuL&B47<$$&!+`@Qs2PEt z+*La8SUrd><_dEMvu$C2HaCYIRWJFjtIz?I)9CAAZ3vV&trJ}8=Xf%=R`d%Mwzn%T z-XwVgN|!Yk4+48~ylH|%_tZj4vU(KDkiHPG_X;gob8&+8`!Tt zK)Ync`Jw(`eh$GM%I*&+7}r=Fpl;=ulku2;+cFjdjBBi>MdsUO#0IgVJIp5KQ(rnv zfWTt9oDN}rp^x>@dL0I>!!E=?HnTw~>XfT%P1(J9o)1uwSV_Sjj4`~tj>P_R?dE=$ zg(9x6dMH@PG{0M|_NMUa+W++&RyBHFfS+gzI1yqRQ8VrS_=IThU>se8`RY*72UKrF z$quak-OTBJ3)Y0KMF>L~#+}a=>CIo+8622Vr)b`hTZgF_wNX+^Ji-^;uyU-G^E}hg z0jLbW=6n}2m+Y04s{|uR!x03zZ)mT)0SM9&YKW~`95@qqD@nG{v#V%jzXmQOum8Cm zh?6B6LJ9&m5#Lbby^WLj=b}D^Td6m;4JfBmt>a}WzxT{Z{z{+0fWNyguN?y34}HQY z5icb9z9byLQeE=FQAvp=!yLKc{dMzI(}%V384ph;JRQ4FO-Epj%AKTvZ+A593goo( z@?yj)Hg&D>_j+9G`6(ERA8Q+_E3dSdU_vj{Cy%l_nXKILssNvbWZWwgf+ z39oqtG?V*qoe}Y)TH0FY*F*kh-^QgeI16r@Fesdl#0TBqLYjWeT#lWP*V~{<=GP9B zh_D8+a~HU|K4lfW*qha%cDc<`4O*2}ChWvwqWE;1aVg1!#iv3y!aZ~9v6v~1kdO#keN}khR(Qbmqv>zV z)RtPw3i3|9UjZ?aGyn4!W?!XoHXDD^L1N}{WR}K1#u|zK7nG&hbGw)XGDA5L9btN4 zOl0gkx!pd_uo~#+U^A;WKvt0(zpWU%xX6OmTjIzBC>N@};wfRxr`*2l zEvK~q^)PBm0>x_K2nTD!GJG9Ig^($eFXEYYq09155m!K8fH5^KQz#POG2Kuh2`gVk zLy2?Rg=LH)ERI!qp#B9TU5873n%_|@l8JxY5|_{6n`h|P&Sl8F#HL(uQJ$gi7<^=5 zbySm0AOd9#^mPWDaR#7AqC{dY%o{Q#m> zXf54$lap(F-Y+UCZ*poDg&MvtjrDC2mdbE5&apFkZiRgCJ`la$icHiMc`Z3{Lv~|S zvMYE@z>=gNy{KG@ZnY$$24n!}P&KYloUayq zz&ISqspxI@PHddmMaeCz*R50Ooz|N(%}}2|NpJmjJ(iJ|^ur3H>sey7Twq4Etr{VR zS$m@@dth22uHt0A^hHa4#vvsnxn{?*uxK4#yZ(^_)PqH672Y}(3&KR4?nd`L(=6OW zLT9tqz!mWArkld%el(6%LVcM+pi2|cK1Q*#hL;N?uAD<_NxLC$ka-dKebxTIsdEpv zePed4l;vkL-%TBbX72BBqSXi%X-QnTCAl0Znx>W8&B>pgG) zO1`=`n?6>f*ROwv1gYM0SGfRJOk2_k{;7Nf&u;@&sMbQS=#J51ru8$30+jt`HqEqr zqs>lsavX8iC0>e*eK))5eH)d}$%ToG?GMfc7*ZWV{1QyBjdr3H`(go+(@VdKqyrPh zp8N%p$~IE9*`Pt&EO_28TQ}T=;csbY>bk9el>tiRD+;kBRyso^Ubbuk2osF24}v3O zCSc23=*nlFpagJ<+iX&(tR^5G<-KGjq*DmAx$i-N(gG;SJp@35Rlpw8J@>|cz1?Wr zvd9(`>y?~3Km*rm6yElm7kHjb5-0*NQE)_(sIC&R21sZW>F;;)tqWUOi(E)FzudHu zd-e0&cU;xlB>!%DJD{Yts^84M^nuM_R^Jm1L5<94;fucc(I=}1BtV%S9-{V#WCZNx z3{E;&%JJNytx$r1dJywIoe#77JJfge`w?Z=C$n?oC6qwgFEHM?>dMhS*1ME>EMm0s zds}YOhwortto0Q)>FhJy#|D9^-9O=#YL82w!*?1Vxr01`RB!(7kY#l~!+(+LBID+G zcSYn8u}@Ym6CWZpf5N`!&`>IdSZs)4Y_VS!T3gi?o_?Wc4+f9QtBOLof9IK-NqI5- zlAck}c(#AWqD@&j2q;QKjHL^|9Qq?w3r1F(9-Q(!UG-;9w) zR*}`qh%iZ3HBnu^adnh{*4KX?*Utl};SsB2!CVJKH`IQBIn-&8UKgTI2OB1Fjb90q zHn2E#KxPM1k}(J=;jW};#wldMpRHn#`A{s6s7E7YP_TTr5>y#xOZMw@5%Ia7h1!QfLnm#_~w&|*Tk?(YPa= z`HQe6k{5cdZVjj2xjl6^;i=i^NN%YXR~t`sL&wLpwwWJ)mwnpx2?NYd^lVxC4eQ^J z8Qph7sGg%V)WoJd0r>UX7{Q!WbtD{~dM5Vn#)+;{ZqXD1&5VYu+lOFrbv%Lr0^O59%ZfSRSfn!r zJSXfBTJLx$!`l6PXuc@gM=jMf`Kb+W(OGY9#P_#GD9gVQqvNx(4k>HUZ>Q#^4)WuV z9kXuzbaH#9Ju@kMB74T>7%LcPL`C869Sk}M=<|M*cIgLpF7fwNTwTPL2z_^p=NTi% z_c)NsA3LGin6>`xOplZ-lz5;xnZ}FDt*VhZ_cF41m_WE+Ux4xUB1M9>|7cFe{h7S1 z?hJO_p?D8rw=?bMCj)shM0V$EDSP#E{I10rWf8iIOJ^v8q&HyRu$>xb=sDa=HL09* zZJsOkNUc@m{jJiM|8++JSnl}p4}8eBYYzZ7;sIv}sb&C4q2R)PhJy+H4s8IrHt^sf zd5e~Y%FUNfA=Pr|pIdl&%e6qZYCWCq>Gf>t@CV4|B7_XAhh!+s)eIhHD=Nc)Zmij=Dr>g*Gyv*Gc!d;}VK9`sTc7vt@@i{}CC$OR#6-U~%za zt=~w~=*v4hH%a+d_*dPH)lQ_hB&EQ5L zWp=IXYzKE&uyhSX|G*33fJc?R)1?8p+ek^p=Ty3FfPaWz zNU3t^vxvv~o5u9iZs0CLsZ&uG^Wi;ndyhBK> z14-N%yu(LyO0K=`+i!@Q;_^K*k*BbWhLUkSD7Fp|{S8mTjUBR|rg@>>%dH1*Q#$SM zoa@7rz9C>qzl?Rtg9hZR-EpDKnUaxssNU22F9_+_S6a!6F=sP%^CHs$zN#w}V~foz z#yAUqc}^?;PT(ozPV9^9IrNLZ5Tq}0Vt?_`l&cxaDLAjCHf2SeYiks~dZ@pBP z9Z-y}IpiWMgtu`)$7uj+j5(S(J)K15DzQCb{7(Q$g03K1iM z$``kO6)5f&HrgOd?V9OEQn-?B`QjUV=w;l&GUQmg@F*q_#_=n1 zs)$86g#S+Y!~y&h;8doc4apy^d*eTpsKr;jT(8KZ4*yisO|OiRh140) zn=Xgy!Lq$D+kfV{;Vh6#V-?) zpP;`W=+rEM*rIZ<4qL}Ef(}4Z3v~HQmz7LFbviQ?)7XJu5LgrA#A3eadHM{)?C?>T z%jHR!$8n>)MF(R{GGM(EJ?Z`Vok><~&swS3eBgCCLT_Q8d?24g#DH-QVlLw*u-g*U zPGCasdj1KIgw>+$?1||5cvER*G_;nA&!GNej$a8ZU(zAmWCElfieXTjos|sNR142E zRsGc$_DDnd0z_ztj&acdR@L}H6erJA=vMPlf|r|7KIA`;lXRZU%&gVR^FdNa8UTLX zI20V5|86p@Hg+EhLLt+yk6*cwi1Xbd;}S%mTXL;Y8zSN!wMUKcoNlxH6tc4NlY&^U zUMquj+#gVCAMM8i*Xi|zJwgfobG;p*dYZifH9wvvIi{7lAbE%rGg&&O&KF=xolwR! z(G&O)8|APYS)16${ee!GrW5Px2D!*-s^DOp%Z8_xd4;9T!W5)rXrau6|Nr$n4pXS8 zn6#`yu>T#OoD$fvTO z)IM1o^cb7akYBI%!Y&DS)*!sY^Qm zcXTX8%X=Xf8b>nlFB_SzQZsVdGE(K+YSMX4PJw{zjvubnZ(tBRh%j5JET*&BPt8I8 zEUoQ*nI0=~A<0!0-}C_D*m0(#Q_`-py|I1on1x8p6gq~lD{OVDG{*M?&UI;2#%YTz z=y|7PlY1Bx#2z-fbznp<VqJ z|E^%gT$|Tdt=;xssQTT9ues0UD51D#mhG_t%7jQz&H^~}-o0^8Sah33^LEQJzq+DU zA}9!b2t>&z4?6{md9N;{ef_B8GYB>trnUlE+j(&^2IsJHR^iL}tN zPnNvEiWCZ?HSB}2WJ*Qd%*tAfeB^+dnb7^NdW}>kW?AN><`FRv8jU})TTal|(uZG1 z#JGWdlBY?;Ex^AM4ww&|s2VbAXe^@Y?W!A>MgCZo5WIo)76aMXI z&P6ICGfy7J2pk{hA5xWLRVn1G&Y<+ZHp;6F(jAmi>M-~2k4&8JCd3)Hj>0gU2cjEb1!L02Gd7`X)~~;<@J|$YC_< zEIY(UDXBTff$#CB0IZFau6!S+>$>7JkpCXAS^J}di>f;l7^bIGiCAhe;vm(roZYvOWAR8 zuU&iu@++_sDA~^$D#%eK1_Wb2dnsC@bZJM`{yot@S{de~CM~yeU!y{fo+l(AuTQN% zd^UPaUzHX7=J{Z42*VPhi(HtOc6+US#F{!iYr2SrwH3b2uG8bJgRCa{@z43X_AF_- zjICkltc%`Q%Q@I|-x%UB>GBS#bp5d4m5^;(PJx$^9jny#8? zu-td>8af}7o7tTms+o3_&pXvphmrd;#^{;Z zy*HUgHWN`xaqIqyJ^Oq zMNl1C53%4K+70d!pKJ*6%(d6m_epqgKWD*`f@|h*s_X#O(_Xuhe*qMJ$HMofa2jA& z0R33h6E6Myv$r< z_^?r^^`CQ-mwnPs4mH9TFMsmo&AH3gwJ@t=-hw({l$h#2^W@z{i|WSBHLF1v?30xjlh? zxr!MWy19_MwnEMURL+HmEo6+KU4K|&=MJUxTzRgLOrgRnT6!v3Hy>1ds+O;z+S+&U zhL{h{^AyX*jE!%etTMw?#)M%VERR~hMJtSAr-!na$bIq0ipjv?M*3&?Ysec zjp85~7G6QrFglw+N*;>9N2&_BZklH`Ds>t5Z8sin@D-c2Tb!7k^3J-4&*Jrxq?y(V zZ_Ea#FZXer(SA1_`r(tollVI#&`iaYP*Qm+OE5XVOVfS@XsEgT4xgoA(L`tQMOhoo zhk5FwUXKGZG^`B?KpIGlL{Y zSo-DYtC20P2CTLxxO#xh2PGv>0B41qyrO}yf_6w!g#m={-01rO(Nnj0`sYtw3x};`qELHz3}ObCpbs z%#jKsN*SCbi1LHvT2BY(vp)kpYByWXE&z-cH`XM`s;c`5BE=-EhpSKu7qkMRs7fU= zjaMN}F1PDPT0?`7Y5A4E$^6~h; z$nDPXyS24qWr)~ey~7v$Q)ry?x>seLC1%dqQ{cHQUX7uPQ?t-MvPi9qfq@3vcq{kiiR`QGCJ0ZA=MZj*bMg z2T#M>`HQGbl%p)K2h=Ny+8=>Q)sm2-A$&A8^~BFZx(3z%W6H_+&7Mk(3TJJd)A!6k zEuXItNusOToR%e{MICoLOL$56I5VUjuY3L0?L+6A57s`uQA$8IGTel%_ay(Hb`pQ)Cuf+w^g=ITabjZOU&)F1N;{0g^Qo^>t{*#--7`1D)j zXxu=3&+?;J!YEP0lWo5>1Au}3C`Im*lt4vJAO}z{?LF0L5cVQJ0U_50VfEFHj||gvmEg}g*5-y#D2nU#SaYPJ+*vzjXxCJSE|xmX!|fr?(pbryIE?ur>-u+vz|!WU(6>Y)_UH*gd6x!N`vOpo-Wh(1^zX1oY@<+z;euN9}I{?pwG|NRxSJ{-LphRJnA*< zoD=2x`oV)I%+F2p#Q!g83A2&vN=QxjQeHp-iI`P??^w}#JYr<$x{~Zx1B~9Ly5U|C z0!rb;W{pjo`qfg4cdAvFlJ;6({1JySlFS0?NRC~pN3N)02R7+3obZSxu%!a2A(HW0 zI|X0eJPkFB&freY2bI^jhqwfq0iedmIv3$I2p&awNW^vvXqPQbDcfdgd+tA>jjT^4 z@mBybRp3&?k7+|f0|&FRWwX$LwY~_narnHt?2_~ z3*Mgq0h+fi%=m+#6o2<7f3uS^hg|@!(V7X+*tOT6UjvhQsM=FeMP-S`W2nG@(S2y- z&dB3PFQ_*$WWJBXfq5E`M0whbov#snG3d>*wlU~%k(@KV!7^p_a8~n{d(ujZ4$?H- z4#TIP)*b_nkzt!cJ-@)Un8|s3*@|jjxWuexg29Qw5?EN4E{5pCDe>mMJCXG<{%r7N zjkhhnk`~gv7iZ43GmD!{Sh}AL*&E3)t-PFU$6ZRjIN$w-!GDNzYZ^@ov#17v44R=7 z19eU%Op6L=$AVV>Ns5cbq*eD{Tz&=1oQd1|!m)p2IeNm2Je1R82GCqIVT%Segj>-U zeD*kuG($BxMT(=>f;~s$JJl8zELI-db^+X=8S+M8%{Ar}i2Y*as;=C4gulZvG*g+z zf#({2((ajRhNW6MEO4|SR|J1?^(7c_lFdYh`259__s(>kqgnF;uL`C|34EM(JP_$v zrjhi;w*x`^aJ@c`F?`&q0;_BM%>Az5Mg;4S>%{s~;$H*og`^(5Oyn8ZMpXn=R2i_P zNI3|=wJMV*?92EfEZDbaeq>kummoS>(ji<+1`B*l&51As17@|{w?J}Nt_iV5{--?Y zqE_1n{ScAFp91HaG#6aB$zTy_^KAWmvjro0Ha`>iKa!$NUaP#IGg!qbdnleaMEEoE zQicYoHhgVms>Bvi8i~%Az_HCDFUK1ee|@0{#n=fC;vo#*wXi-`@1AuZR5ABsuu4TX z0A4S#XQADfxBT)e>G#lsfaJAuX4PE)_a)Oll-2+nuP}zpbGK}8b<3kR;vnaREhyi) zSq+udARKs4n0-Ap?hW8iEwGOol-PoaQp2j+2*0s0>qLHaqy5|nNhFJo=1F+)d~ z>s`-_6Np^BD{y7lC(IH?_TRtBI4zuP*YTj8Z%fu=J*N7r80n15bSEv0CGlcpW_R_| zUG1zci!oyn^*tc#_PJVR{H^>GR>mE$ONXSnWoe5m=r8LGP<7Tx&i_&l5y4INbE|Z| zkxmRYD|K&=ZD%bq2aLOZia{DW=QVZ#JOz`hPhe=3kIb8!4ZR?xEFXNNWH-gM+lu`1 zcA5%5h{qhG7m{=Hsl96z>30Tf=JvIN)JV>x7=;p z8t&i>O`JU$Xq@`!-P@&142Uz7%hc&7W0hg+(-D?_H;ReRcNXU5l1ODFm_aWy#U>?F z6iuHY+jm<-L6?l9p`Wd}ykt*}>@vC_A&9hL2f6 zI*SLRQab(k>4_Oy7=eCA!H;79j7|*04n#z0ABc4aYC$AU2G;ZMx$av2uV3Y?oava8 z=!|zNAJsfQN$*D|AN7_0(7lhj$TO_}BhYujsted-!_x{6jqfwMvIQ`%$zgB78>E>U zXsd#5J+KmiM#E38#I7wqweA9Tp3)o135nUWVadzQ7$(9q@-bt8oyt#*b^gT%KFfm< zC-%pD;J)5$Q5-Z)qCVSk9dMycnfiv($hWgY1eJSila@-FwC)LbS=&~EI#M4D0v#(+ zF2ej;MS5^J)fET_cddsk)X2EGPD))rhfFbSx`yLH&`7eyz#bB0!z-u{neGd*|A_`) zkl|rAe)$ zR>vYxVpv$9^(w>LO*^tdr{H>E;0Vqyz8_I(6C|V~^4WQUE$(P&dUs$?;gG1EemaN> z_zO6C32K*fR`MY(D($;sg9S1V5Z0Gxx(>2SSGgJ4K&B5Uu{P z&?Pwph(#W@=zw|fUCOI+c0Pf>_A3lmI6Z9Kl+0%{KtX&ckJ7891z{pese6XGIr{rH|pX04zH@67) zUNds$_USlqDMg_W$4xgs4~2Mvx2yOvW^A96+LOo-jbgJ51cA(S#Zi-F)v1%hvH;1tpWF$%a&Fvh^v?k?*2Qd4KeL*3YHKUxi zXNr5YsEk1d(Y0K6m+BlP8wqC*a8_!O`DPNjy-mTY1gQpi(~{`n(%{ulhZX#wuzus2 zVj5sor=6^im{wy6OBQUB)A`G~#a`1ab*I>7#6&cuavWE0EIZ^(B9B-{ql3brzzgD9 z6fAUFUE_>wCD85&_Yrdjakl7G89%H3x%kRy;L&cNwxag`5@Aw=-hsHIHfh;_YgN%+ zdZ$>KBT>cTWWoUfYu!kTdEXw|w8j|2N`JV8W4gyTgJGt;969VlPE}7A`@JAC$ zbOGuj>e$h(Ci~q#%V5cC4J9#A!W;fA6u0bTX(CM0l|%M_hLe#DQ;(t-lT4e!7>=cB}t(w1?{t#@LTc?U78TH{L9r9U# zE)ewp|CBpoI-2z+6(WMT5Yg*4Lk;8>I)jz1eoU|kRkv}?rP~G}bk&l6$C-O|Crsuk z5550e-m#Kv@DxVf&gzWj`l#pKI_!Zo&Jfi!e^sdXlpsP~ z$`21;Q9)3dPnFljnbrqrHWTQ5S%Ihzp;vqden?a0*K28pp6z&?9iF5PA?Kcm&c&{v zg7PR#(c+|b&ME^A&R@1k_&-KJa^+ycWi&NtY_4m1_h^)o5ETr{i+>&O6}+D*-E%!c z2DR-M`8_si1N4h8W&f46fc4?$Ctl&0r@HTb#KBf@1tHNAsBQ?01jK`I&^D^VogEKj z=3P59tN0Wn`DPSLe|hpH;Bf?!?I^>f{J&oc26{>3z9>fbm$IPNn48>m?*@~< z4lG5ux~1E)$%hgtRGRyxO#jx7+=>kO1-#z}H>im#Z01u=Wb1YUh43Qt4|yBzDqmmD zyBpK29#O4sn;F2`xD`1kWk=qRBPZELCR~PA5gtNYQh0gVDWuQJg3W;D|7{C!f5Fy<`Z??(wLvXA7jYu5`JSg~hT`(Key~s` z5KRX{%twxJ@&2n+e#j)^zyAhC+MEtNHXpid9fJvRgZbn7OLvvCS>4N3dAO$sYCp0E z6yn*<>siMqeDII3KfgI(yjH-T7lf~+z;As?UKm9%>Mb>u**(IEaou0r+w{LK`d*Rr zg=V9$l>-G2%9#=tj?vj-(0DSczlGCKI6>VqrC;nPLTHm@s>dBriGmC|Cjfc|Y2$DA zk*W$f*kx=p4Myk{?j%nBmA^Veq$w)z!oWuTBYx$Gg!rDv+J~$YwL9fs71WOq#jac~ z<;MK4yK!Nd%7MJACQ9E0eor>RDxJEqEf~zgM9vTYU-NuX=+{x!%dd#je=y3+n z&o=4~HTQL)3C}>=)_z zG)}IAV4ymih3YW{(-deQ>7lkCluT6{~Y1 z=d1W`zgs8>Oe4HBP71hP9A# z9U;8;3j;73h@P(`y;V44`iA3Afhfb-RJxw?ZhMLOc6#liYpiw)gLW^Q_5KiTu>3)8 zasw#t!}mRCjx@$Edy|I3gs&1PzePRWeq%63xcwckg_{I+y;I46(8|XyHCt(q#jPQJ zJLXzSUQtsySG@*8S3#iDB8x2E#@nf@wnR4r-t)~_;;2Y@YzVIl{vjTT3wB+7^Z554 zbhwSCxgXmf^dST~h2;sxe!tt26}7qa(m?ae~o_?PSU&TAQWpMR4J0#H*Bx)6x`ZS zv1;)M&I*!LI83-)`p?qkqs!#Vf87>2d7T2sIhqZ-#qH5&vELkNi#}h7;Nd%5C`BH4 zMr_rohIK0w=4sj5==l%eW6nK1E#1>I9B15I=nG4q#MprU6xFu=T{SIl?}0u2x>E0n zusu_l04Y4Kk^I*uQo?HfcnGS9$e}4@UTgIPvzW`A!uBg2H8*NjrZSBaEfM#D)&P}K zr>j8y!6lwiJ0Zo*LX^=Y?S+$3VK0^p?SJn`^1EQt83-Q%xNMI;qg@;j)bodd;1?;zpWlED9e9NME?$C=yPT>hPk&%m>^k!{?PSHh zS06I0JTKRj|M6e`j~vKSq1!Zs^ap3IYGrQY*)jX zBS5JYB~xw?pFPJ<>`S{m<#BRC>U}PtWSu_ePpdSBKNGxog87&1CYyt1tyk4608oRF zdr*X6+e@5+Xn`PgSij{6<0B;i5fmU_OuJ0&)kgXBT>$g0AGPl>oE=h+j+q3VY?B^* zi?rd!eaTbFD2w5O<3ouptkAM9z1-~-@42j;QeGrFx~dD9aJpnbDT^<_LVNucr!1|? ze|z1jG%vABms~E=a0H04Gy>}j zV!Kd``gk)K5JRoDVj%xEK2Hy$KoMJ68ptjO%P5&#Mf`)`E=L!Z|Hn=N+@1-Fx-2U- zYulN(ihD)&ca6yg1bBwnejF1!pEK~*cK;9Z);-Hx*jm0pCX}(B&kPC>?TWsi{PS0H0Shk%yMPU+>oM0iHU($vsgC`Y05{qe!A zBN0+~hs_Eis=##E9aOi?P~1k{vbI_crd;|)9bhJjqa+bvKTh-jc)QnLj$nUL#krW$ zEA7V`dnnwz9Ft$Z@7}=Pr(0Mj03W zVNJ}f4>c&41w+4;5rx2rpyB>3n}(_bg!kG_cR#jpRek0UbFRpJhrq#shd}CB%lF*c z+ouJZTzR!I;|F5*r97Nzp+Bqfl>Hu#ea+*R^m^F_MxqLtfpr*Ic3b9I3SRQ{@b@R>cE<)=7Qggh^*k^#XZL9aq;I8Xv0G1%m7?UlHeWL-Qu@?oS@ z92)XwsxB=G(aTQqOF!nJ7kBC6xa;goWykqI_I2V71-ZWDY{*u4#Qj}GRWBldYYSDT z4QKsXzp(i0Lag!;>KNCTxaDTefg0EA05o)@s&1)3zUC{6Xds6~ zRphzw35La#53lP)65)i={kcb>z`$mta4C%oUagjYF4(M=^QX06bc6(>Z2XILw-^b# zU5()$_fcHzm<#O0$qZOit;xWg2lV+ig?zAyP}apBdCpV(7Z(~|fdOrPpa-b5SNgNP z$1zV>MME}~^dhaFGzV9#T;M`m>%pklqS#WRRH7-Z3jR0=VK6F42s!!Ml@Jajf8Ve} z{;#FD5<+laL~xK-E>=fqt$zPNmeXXC0&@c^C9~PebCZM=+f{ETAjCYu&u=kZRf7Y>VheG$DOL;$~$#{Z-BXY;Lt<4uEL;=~$%i8M3g=EO)vm;DlBvw70`UY)Za!sY{3#M>A1@t=q7d zGDzOIeX)yGUhP2zS7+R7QL*{pcLHE$8T#e!z~B50nthwd4Bk~NzMfSUZIt;rhn}lD z6{Mp(w>@HTHZt35U+}--OjV5SW;#S_fX} zR^!@4jC9g+b~8-o-QW5a63hcUMeU?cmE|cT=}eZ~P0wa~5@uy5jbOGU$UwjEw?2#L zDpe_eT@1pO>Wcj7Wg?c!g@(n9m?>p8x`tzh*bK9`qA1Q;ld~%^-bFnQTI2##SAhKVOY1?sN2B2&vZw-XIw6)2KU{w&=kspeY&hb`&B3%0M17iM)vd1j zLbBRZFVY(#>^0>~q!(zUpm|x$zC!GvYBU%4*mMBWCNePLLqh9q&JKpBaM4h?dZ1Y00>aSpa5+xrv}$ zk-s5OTzN>9+E`8GQDwr|@W9<1>9Pa`?!uNa<}_Y-aUl`qCbR|6A8qCPq;OykJ!#8q zYc+Ef7sRyw1KPYig17tHCzkd0K6q$S*{f-3kl4liUe85QQoSdV8abqJ?dp6MTI)+> z>xLRQlw*fVXp%Q5g#jR2f4~ka(xIJrkL0iRlI}<`Avls7|MlWzLa?5li*N>Cu+&3M z?NzP`v?`My7#oNVJ^bY%)yvJ`@JtTGbai;Hl4T^_N>iC@seAfmFk-)eA=tQK(Uh$_ z7a7~*;~uC5Dq{mK++VtxCfIEkU0hH|>u75+o{<~p^M6n38AJ`THBLqGiH-~J!TQ=r z&fAA%_cngC*{+oa*{0RL>Mjcj;vi2)*^BO2cHy2{_y~-_8;EwX{I0*JWOwsE{=wYs+G)Ga( zn1CiqN~TzjQ)ZXh?al^Jr(2pXMwAxRIpd@EN>*{7F@Es#wupqe6aHN33SZ35SE@~G zD0Q>BvwP~-n>tv#r--JXGJywnP5-Z2>YDn_Aw7J*V;;P!7Wl|q_00S|9|zI}^^1puK4Dvdt4Q!Lzw91reb%^7gQB;BHYTA3LNb7VDIrtG=RkJGv4A*jN31!DD zz1b}{r#urdHyGW|SOw7zc0un#I_Wz{g_;+9Z0U~Ea}4SlpPkNH!3(Vr$H_|zK{`>Y zt_CyZIYK!2N;Ce_=%1e?zl*B@aZZ%QZLyered-5-(FshnP(ywXRSX?RG=z!L0gt|9 z?&f4%u>fzYn*GGI&Hgqkwc93|_9lE2JtY z+===zSiHXravFPTeQj=ZU0T_lL)Hrrwv7m`oY5*?NKFzr z_l1sOC*_C!u&NP|ImvXrL!qrM`07?}HTv>crGH*7_0#hdux^Yf%vG(KJ6nrL4O`2A z7XmJ+g+gFL&}xP*)Y}PM!+4;KkybQlbVrR|if?2@T8^E5x&KW5q+)9zsHV+S9snT2 z7t2Meb`Xd9{zFt0Ez5%c3WNv7SGad<oBw7nT?CvXY5ZxySL+EvAUJy$(yert;;_2$N zt-U14Qy{@q;uFo*uXJ8!1jj)avl#A4RTC8jVN$KZ~qX$Hd;I zNC8!yeF|HX8O)hQ&4A8i4@q2cVGVu*?zMApBv)_wwZ%SKgtb%_DDF4+nV{#be{>e3 zeI5TKt57GGF;TZNl4FX*i5Qs0mDGFAkCujmW5{zNNK)&;JPpg`YDc_5GB0aOVxjtv zEyL4p1P<@}#E4RQab$#)EjDh>Qf3>GsvCJGsQ{z^6*nrv`1O_3sju961mS}*e{Y%+ zZ4O6=fgPhemP@vw)1^bWA#8K{V&v`YqPyWH+soKk6_t;~1|UjS=OpuxehmVno?4)^ z1l51U1lYT}wa|x&sR76Er=qpLlGqR%@kjBipcaqA_?LYo1eE2Hy%jkH!0m*y-8{Q%r@|^T z!d9G``qIF4yp;iHYU=dGoX7d{cG-vejuBXMI?iG6(20^6jO*rPDB)*-WR7jW@2rM7W(=-AoSM_V)}GB9V+}P(lU1(;@E$R%W5uvrwA#NTcVn!UeTZXUtAU2+ zUR*9lBdvS4z1TGp4TN4mKWWYA+q#GW1VG`Ds z8Ofd2p}F>%=H_G>@Wh8lpI6nIE5=JJ2)L7h14hq$h<+j=^aq7ChHwV31Q3dwAqdFm zU9jO2Y?#=+w%?X@kmgB7G-&q$?!Devmf7-Taq9MZf9UGqY>3xigy=n6(40~q`@5cF zcchInfLfB;m4>om9bAMC%_AL8++QY$!q#~P&ViADRH1<#oLFMw^Q{Nh@9P7?pIKDt z9b0t!n+OdPtZ|J3lUt&_MU8*mt)mt`I~zH{_;Cw#(wowPyvNOrB}#a(9JUUpR0++& zcT0!yc_JM|z?^8~*z(O(x>3qhFc2G{#nPPl{NHxfi~Fr@=l|Rj0vzF2Dak!zj%7}> zqa*t75Wx&KrIAB^f+{o+gIiQ?Dj<3UwkWW~!TM}7(-ko4IU~ec*xYPu80&P76We&t z+3O#|5v8ZkY1|M)nAh$1*|!`qiQrXUNBzP8N+yVWxSXv(h+uLVAd*t3Z5ky9yrqGN zXG+J|%AjQ*a9=9`VbbG)Y5i2x)!!k5DeIs2+V$qZk(N-W4zY_l8dK6Q9c>27t*Y^R z?s}7kVBQKhjxO(4|3SfR%dpZI;@1g!Ar}3FOxo&<))=<^QWJukfnnB)E?LKa`ki+- zzpq?~qNwD;qRy?*N}}&fvDMscA~DFS;r?jFwjfB>1|%IJQE(j*%H;wS=^gFI0DY=) zwAE)3b};9nxB$`)T2GgRz(kU=58!Pnvvpt79!TS_A$01(IPU`Zdh^G3iS44LmmjS( zFw1h)YGiHYv;{@Lzxyfi{9OAPg!)7}>#@mp&j*6hv<~EormgPTho+Ie9oE4n*?1 z;f8b_>r!}ws0|^#ea?xRbi-x5xKKdoy$m+x$Wdo$D+%uN*aNX&nGbmthfO^P&8sH= z_mEL+GZJ)d3QXn=(pA7dXFtz9tS~DcZ2M3==*^~Zmt+{kvrLvpEBa~P0)QSf3q#s= zJeH8<`^3LKVa&(atE`If_NJ-9FvD-^=Y1-kMkE4bAAn3v4RHr@K9@^&M)j;-pp7m{ zdpg+A1sJ6JnWwa|Sd!Qw&984r61_2ec%}Lx;=<|NoVmn`2TnQeME{)x_Yv!D5~piQ zO4WO4rjRZJIE0;DHM-8lGE)>uh!ie0-bF=cCj>h~j z_M&#*yOsLH-=0_bv#h)QFSg>#*`4C5)+9_!HbLcm`Jpq%T9<~jDc4x7N_!`}>9h{N zUd{d-pwgl6ZC5KJHx&qllf5nrrILs^I8EA1?jFKu;1E1@&=p^H@r+1eC#03UCF3Pa z$3Jkbbem}KFE2JwSMNR8s?Yx3Ew96=TGG{LpetmgI-vR@0_?GeCCQfqQU81$!xHR{+ok1QA-@Cl?HB zZ&1a&Fur7nXyKNojPWzcF{U;Ur zuDf-U;@CX!I7I#nR0v0R_Ac;=bt}Fxi@FeyN(y$rSTj}|pu%z*5|0W-pDkMT}6JY9o60S7BixwvwUN7yezHtHnX%|+kN!>@A1zV!v^tf~*6J_qhQ0ybp&M9e8)P6Tn~9 zs|oKZnB)y80PdPP?A^Nx$HeF#Vf!T#X zNlg~YVUtua1p%fDmXW$p_k}Bo1wKqd=;e9R)p!%yT%DnN#@Fs|;*{J-ZD=7)dS`vc z$p+WV6T`ty(Tl`3)FH${dL|S@z_jx6E1uDU99FBU`E;boe*(rY8IAGJ8s*IinjJFh z&Yh_cYzjBR!mWGU={@Std&7(AU%}6syGx%y7Xq=}|Ae+vmR%Y3#OJfsOe;k@Veb&( znH3|UipuDEZQ=wO^vvm(dW5(6cGC_G9+pC&5P%6zAngS71Okwh z|EbO^>HBSkhBzgL!}{lPO0)YmvV2h>bIOt-=G~NC{k-^&pHl8sqr*k2un~U`Dzc`DGI*B}U(XA5o)(?fdM~xxqObWOT z4Uf)fJCg=hN_GQYRVV+uajDJrlsX$Y>7@}p0JnEemr=~Re~ z9q1W7U2PLsjUO1V%tS3^@z11#;(XT8YqIW*WnKPKPcOnb&Zd5s$#_1V$lQ%a)`KEEGMqEKA2Y3*M-rsCvDU^Pd5Ur0W$=Jav z*VJBoA3k#bTI__@sLFDpaj&#kLBN=8^N#u&PT@{XbGRFJr4;5_#*i6L#Q?h1&fpzl zm;Y{Ig)bGteu_8aVuE*p927cv`Uu16Xe%o=tv{1HTtRr)7m5eqXp?D*(7Wf;iwG+C zj;CAX{r7>c#(PO1qv;Z2I^-YrHRHp75DyK6v(iZB!8AsCcl6tI)JGRBYKRy%u?B94 z#{x)p`7;NPVT1cFhaVtfig^3>p1z075^5;TqT!@~r=Ih{N|ZkGpc7`nH|!LEO;<|l zT>sl3)axoOy}HiJ8QX}EN@GPrIR^SnJXdQIiD1CvqyzGPw)v>$1{|pkn+mjk_W_bW z5?Vhx4wT~Tc3MDxA{i;_waipZ|W05v{On*Kg_V~w z&#lsCCvoIPxT4{^ZZjQ+x1>Kjkd(zW)5`5veNXHHq^ad7U&g~hH8kESK6H9I5_Cqr zs4rW4k832)D61bKuuXAllr)I)i>AMa4L3u2baE(hXHJItx7 zaUDMPP@9NcSLqx8=TEw*7791mWg1nrwLefdbop%Mxil1s@;qP)kOw5$1xDN+fJk zM)C0)yM4u=q;Z-wRV*=^|&e52y}q4-df|e&9DK5;9x10o_jSz;>#dch07n z`En&fxV9?H=m&4C{R|}`aK}Lg>#$SsW*}X5nx`L;Ryha^4T)VG;(NLtMOoZU4AY^G zw*<@v1E+is%D?J<1K}vxe(0yl1Fq~Px&E2Cy;Qj~Eh%rbB?x_n^*f5l%wB^n$>jE# z0kGxhZMro-NjBGs`y3S#LZFL+S*=v`q1GyQm!bMtDzDXQA33?euKMbVt-6Y4Z+`AowyCj)l!omn@+^= zF2jA-Zxkm~Hj)D;#7>UC9&zg<7eOlp^JIChX75;{My=S+l1!wH?(BlL>&I=dy8gDw z=`%zeBke7~7{eFEhY24H+F-dVG&Z}V*C$9v;J?pC8C91!PQ*YXWt*d;`i>-TA+IAS z+h~X)fJol9oLenG#y|cW$du_e0sMK3#!-tYavz7J0dfBIf?{Dg7(!y~3yr^2lr0!b znh1^>x?!zWPh`TK&^2k$9hHR#hmtROPp(e2_p5Q1$Gc3sQhvAZnh(h_X1~;xuNLA5 zp;9Q){Y5Y9%vG4agWxYDA@=3+G?UQ_?9&yqFLaH%R)b1~NEzRy34;!PuH_z&lH7pZ zTCAH)#cDcgr_0@d=e5d$RVdLiAJ&9cX4p=YbZh@kQp<~Yt|RJ^zL>as$l&za=?Yae z#}bmcMK)j+R5N*oLTv0D8(d7^DCxy0ZS{g#xb{j10t>&udUSJLMIdY1H^$qyCyR_rXZ$lV**f4;1-lK3YusJ%XWH`rY$H)D-v z>GlS~Lnl}%k!A=lcV%D5CrJ+Pv_H7+-dXcLil1HhAlpab@MXW`ppcOz;AA>wa?7B= zN^tWY7k)yCgk4u zQ428iQ}p3b3|}RSoiOJgDdt9<)r7eJ;ZWRSTy2k}@aF5kg6-zk!&2s++xysjLy!3F zHSOrVGa5?dreie%GCd2#pltxo zJJrbp!%;bl@s6?75Q|P5(uumER=^Q; zUiN^u=b@%1Sge7ig%l5H)R`dM;~m3Tfn|S;$)ehaKa)d6o4{Mpib}LIksU1o;pWyf zF$hq=R1#0r1lL3%7|KUF9hE@C;MB17t|`Y> zAzU*efz;irjP%J~j>e9VR&({a^S{ydMZ0F>%GWipMgSG)PHlm~|8( zRFLjMEN2ZJn`FnOa$Ac&a#%tyxMX5Df1W+2?Wnpf&Cc%pp}|ihuQOE>_=|u~P^eAC z2?r3wI+6)R>ZZ_E0^FoHBV#GFha;4f&r`E3?cz)6e45xMn=+CXTKNAXr1kf zTibjo^cNGZHHN7wA_=KdaY`)u5FS>fMQ~vS7}t$}ItNDlMF&CTec5JF)zwuJFJWOZ z37q}7YoPZ02*FCFJc8I)TkKD=S58~(btz=wA7NndsZ5I|ZipTwp|6GfcowqkzLdg2 z4s7Bc!LZ{a{p^>1I3x&=XvXs2=M6vx+5A$C6~y$-C()ODmFW}NVgOe!Z*trEr}DHA z9G4hb*uNhihwZ0d6rpU(ZrWNuwV$=pbAz91cJp7-0|J%e9fG_;RZfS^-Xw*9p{UXt zjIzb?@OO4PVzHR@U?ZIttxwnaO;-oxqYcD3pc!|xT)4Y|$(U4fuxc)dwvP^Enh@XpEjXgtaqBn4@bnO~&kzu~B-}Qm584EIavH^Q$1TW2Qw(xSxY63Rq;!?; zAx~zX7_^4y9evcc1gdiMA)k(uk^|-Zim`TH^i8RUw);fBDMHhc^jm=G#6XOht;$vy zIWud2OsH$($4O=&``bBVmQgkb%NHuMeH?Cbn}>E&wccvpI&krASpvyx5Rp$BKCN1D z9Fi1cx%0sF{Uc4neO!dOdvff;?V3X!PsOydAx%^kEs*J@j${ti*NDl`e>u{{O=NigS(XL`CTE-B zCSx|dR1)8}+cn#6d}gi6B<(#)3x<`c80E!uFyfsPMQ8LmS{4L{aG~@kbq`eOZ|x)m zWmGh{EyA~ZprTRXyiNwuw}~-U6sxR961U^ynoJ_TK(lD0^6ytro|YdavrAc&4~;J0!)NO&cy1{Bci`i_VNB-@M` zW;pXt8_^t5t^y-@_eM$5CKk~yks;gIpMWGf2ND(b!QBtrD?de}v5dRtzgX%GC#Dk)77KeR_9sL$0y+s1uyq}v09P$G>L}kI z{%hgd4_;RrXRLtKx`cU)FgxP?uN0E8iO`PL)J>=4`$216JRCol>6Ko)TdLI;Do2c&v$s7YmYoq^cn26qj@Je)XFv#~3t`Pk!Q#$nUeIA}Cg8L5Z7JMIjL7 zlZ95MnB{s!J{COxPR7ZP4m2dVMN=ci6vXQ@tAV^E(aVf43(4l%_GiUlH4@a zHhUC2_Zn1}14pW(|8BerVab`-YaxW56YGI^3+)Ae%qKkB7=pM|hwVmoN?4Qi|NoFm zSdcXwxmz=Fxw@u^YeLxgeGBC`NiQ&XUv@Z7n$=L3gqPmgx!e%C_Z@iF$&7!kfQ82f(i*i;>%t9kv{i-9d8Q2@dA}u$Uty=yrBK|9*gF(20@!>SGJ<8DV<%tx#VBK>J{0 z^F|Xz|2?}@r-)ENq)CZ4G@JHp^|mR7&w@TJNP|x(78b+nAIO?w^zKhv68V_GrNQsM zYEx}z;a>4sVoR1ONdy#(?Y*d1bXIle|M-F?`i~u& zWOZS-=pG&e25`UzQ!fJ2?KJdK*B$@)p--Tld`&uy8RjHQDp|k4v&xb5Ad@$Cw^Ou7 zsR3Vrv%$qD5S#M>-O;k;C}vp7oMa!I=E#*hl>B1AB6dt50Z`OETlor9$Mh0id8f^4 zB~p`}fvVa@i?THr4QRcG1VHBHIt7aXlN*M-SL+0;D6LsSJ68wr^;w1CaH5s4m@(X7 zS8?_?E(`iFz){k6pV3T@df?#~h?U%vbD?rqM&-u4>=8&IP04Gln@)w)c9(^?oTkVP zX=UHlHlp(($>1@DpJhXlh}*RLP<~TmKj^8$E~o#$_ls}CTxMRY{UO1!6#lky~>j>S`^xu>|D9j#ExSFAoB4h>b+%I(Bh?nuft+ftA8pLww4&nRTw zTjZ1?=sHC)T}9X*kTu2+R!6xQ=S{VTG8L;uCwyhi{Oc3>;_t%Bf&lPj4OSvH=>mRe z#?~qB-1!Y*JSC29^Nc9Z&Zy}x!0J2a=sDvpCdbhLX56Saky-f}c2M~6W6Z8Rx1S+6 z4c9DiAeCHNfjZq=k=;xz1K&T(<=>4isUXf=w-V1Kf3vt~K{!Dlv3h&}3@ROW&k0EF z+THil6!}*Z1!Gp$)VSb?Dsp#)u2WbIuo^kE2hAa<2^!TGOXumb|W^<#36luk4bAEZo4{=?`RUyi11y=eN026Z_(V< zAB-;K%&#>a1_|fEvaKHi*JMJBA#L$@hIb;XPKp@uwl{2Xl&uY4Oj!yA8Y0mNGF6Y1 zlv11z5@cE_ovFo0ly%ypOlhWC$dW`@qA0AF82O>NMr>nI@IhV|O1p81VuR@kiY(9x z-pa6{0@JCs=M}}dE{bBm-#4ed!)ZKO2kK!Mib88$O_!p$7*n5)ThC4-aj~)E ztkd+sZQ^2xb5!^IsN3@l(s34S5Xk416ia=|Xk~fgx zkYj(ce6z9srKfGzji>#l%hByk6vmyamB#)jTwst72xx+g7PfB2Rhz5Jg9kih09fkH zBG)f^-*&0i>26D@b`*FMRYIw9L?i0BQ&obambdx79=mRPN>in`n@xt}l^>K3TpUw2 zo>_|Wr8i>Oa3$iF6cqbY?XGmb0NCi5df&94ZPT1i&ZnZN&BF|JflvsPv^6pQQ6dw001X1kcbR` z@hJf6rp$`-`Fzq@F${>Dp)R`Wu(zb>R6ByOP6op6N#~j@n&D_dBvS#OD-g_O5Y1qH7V0cbbzxY#i|Y**;2TlQaV4#s#@^#5>|#blB%v7IWOb_i5@3wllsrve(bQA}^QSwyQ;%X}t|_ zWeufzrw{|FpWEH#5i`Ds!Hu$qB6{9{-bim_FArn4(E@;RAb?|WlNz^?r77xUE)k7Q zT9TxXCjdO26h8!^`z*7aXcVb&*~KuJCx{Hh9BzQH`6)&Y;2DMv{u<5GMl|T__22Tq zI1t9Q7mcsnj*6?kztL7aO}2%nN&6u3=*1j^)oSK05l!XnT?~78?O);Hb()79Rpw%` zwEX%K#e$v}L{1I7!pmKcs3uH}q9v;N`e8rw!%OG5*>DwIJc6rN^}oTA3O9l1W`BW( zL$w)x=x_GF_TdIMUf#h}c6zKESy-XJnYeiL%hkhv_$vRM`m>>nR7IU<{8jg@EU+-# z1Rdn2|G__L{O+GZ_HhT0WQ(RZRYcVRv_l9vMuJ>h|YO?0lc+4AGCp$9tK_syJNaRr6vK9rjyO7s`= zJXlN5Ae`u&Ia&Z3$}EW<*GGgjdgs|&9y)^j^aVCC^RC6YprrikS;`}a#0hc z-zHD_s80M)-&7kPCJr791Vu<153jiKaD3ax@(3l-c-qM{J0Ck_lq-nzyC3xW=tr?! zq7>&n&(Q3B#>@-=nfhw?%id?o4MgRdhpSu!icn@@=>jm>rKu`)@$4_OcZ3SKc<9Ot zM9NG!IzoDt(}riJVaTv@`TF!_;n6YVH)Nn-$-OC+#Y1l~JwqnEc;?u4s0M}zUOaKE zwLV#h9RnIXcupNSQeK@|&}6`k$K5SMfQ=_V*;0zQ<*AXUqpp$1~ zL5Aq)iK{r4TcHFd`h0R?Pg0CH(aA%SxrUPm7tfebMwrNV9e5%YN_4PSI}0=1`~p2H zOOtOH$XC6`$qWN|yBcURl~%{gM{4id;tY8An3Z)06!`TSw(43yfeyOq2$Uc5=+Wq@ zfa=QxM~??iZhN3C-|+B}Ra~z(NcmBA&lm!$4kw~aaP-99H-$88fo{}H!MjIHX5BF5 z21id!*XgEX$`9;3F_CvKOql|5FrHg6MFJc>**)dGg&G<-dLpEuDr)ugAt6^2R7D3n zPej*oPnEF(fyd*YgN^d$NENAIpxN_~?hD_?kqHNyGoN~@V(R0-2ukh-sx0aS^hUg% zj}|NV`Uz{MX}Hqj-7}-T>9{iL7f=&ik5KLSgRh@3W>y1NF$EZCo;q+9GE_{Un?`!B zX<4QK15MA)q78FEok!inn6bGc$KgFLTDA-g96cZ2;+BCeO9dU4+ommDVCTtlE~OEH+&b!f$X~D%NUKG_B=mTkp|kxwuqo1pgX2wr-G42FJ(TX|cjX|P#_nFdpHgIDRhel5X)Q@xcBIv4bu4fC&$=B;H9>uRD!|!2dwc6a( zeCz6_DYQh$cHi(-n(;e2eQv~HtkGQ0pNtZNJy+#+$QjAx3t`1QlxZmoRZZAeQx=c~ zYuX;HoC!X^_Z5|`^c6#oSTV6c&An!*jya7;vioJ* zJhf6%R`xy%B^7?9>av;$FFpRG|G~v5~_+q2nAD@Ef4gw1gl*L$aNOX~`2j43X+Ia1NpcmYH8CNb87H{Z6Nz(G|S(DUjx=K^G z9CfqC`_!Sft0`V=M^}u?a%&kZ;xOJUeTTxOgABTNHk5NFx_8#Z3N-rOLD)hWaPQz= z=WL~7%&pq{Q0Gn!Xuiz%j{Gl98{Ipw=NZaX)xuhK`7(5np76j>xv-=#{d;O39hn1S~;QsDXQ(^R8zg5#T(q;Ef}D z?xa59rQTrDD!g%S(#^xI?_k2L&$3u6WRW3+%HDT$sSoEf)*DYB&u0vnJH&50Y0hND ziX}7p;DI&U>Zd6(YN&g<7{*Qk17e0192qyjMbA6}9F;Qcxx*K{Txdj_Xv5N2xRfdf z3oE+JyB~?#P7GIkX(^WO$}?RYWG%EwY6n`j%)x=(8SS>y;6cMy43$HOVM|DPwG{%) zoU)Cb%~U76&mE;$P8`sRbnWPW2WI~5L7{8nLr>R{wsvM0v~&aoW3hCMKxWwcB0jQ( z-lU++?w4-&OY0&HSsnrM2S~veVOYcwOn=(3<9#plii5O(Z#!o>;Jxj5&m%)9?G%hf z%dDL*khAB-v~~s=b?ulDyxR@{)7;@ebH!2gW5@cfgLaw`A+24hskWo9IKMrEHN|Zw z66d#v$li78f;pY1D46BA>u72_nGPPC6IQRLQ^&SIvpxx_K~@T?R)~6s6}=WE^?@pe zNGyd*OVfjL=q!o^7!zBrjx3p`#B@XuC6mEXrzwWC$~1Md2A-%Yw>Z;-7AkkXR(R(T zsiVLFNvdu|GAEw$}nhwE>Tj=@sPmdKUw;82S! zvSP_(5|2O)(s|ShU3zvTy74d?GL5g@hD@t%nfA%kRzR;hxmlLZn8YUi?5VXjPo1bl z;VdsxRpO}=mw4i7`LWevCJ!CU@@knf83B3efkMj#9m?dmnh-|6O8ypVX6Z2X;RAx0 zc~Pdysg{E)D0cSqLC#>nY?mI={zqiZz z%ZsanwHWIH&X;Aro^=QJdb{0rnu;*j9t#gg=)#i*W=)iLb8r+vXbM^XxTS;Vm&ie- z`Oluf=su2HaX5Dp0bq>G9Eiu_nMhhUmx$Bm!IZf;kz`qhvOt{&dhy_FVTNbxvUyen zA3jYn4^+ywdFm+@Llks`;S)_5aa(xK5qzSF&NWe6ZeZjxTMnL*W*a_liCT`|C8{)A zHjn923|n#;V|3p8j%D-*=Ly3DZjua6c{Ru_Wb-H-acUdBtY?(f0)g zuws}iE>U8FtAr<+mq2v_{}%|60dk-vWjK@MR0D#~2s$S}6t0;NrbF@_A~7X`?mHxY z))X)2oMK`=y_wo65=kXsw33O)Ny{<<02kogz^_u{;>k{F4FNd;u^S@p7ilSEVtOb4(Y`BSA03)8xT>_VCG zdyI)v1d=4kN>MaEJaK24ciMmw)dpQ2AO{%n%5GBODfwed@$v!AS~r zicXIhx5eXS!hL5-IRi*XQiQtlIe6f6^d_)a?L0~u6(X(A;-RCD9I4%4n)emKY4OCf zv}uEKhQg*Cs7(BRFs6;CG?B7BKYLg4vrzaxp9z*U4Gr7#P!%1UHi#5!&>ELiIFaIkit@!BMj`_BLTL|x?O|= z5^@A{Wm0mbW<$(`_3R1rn%B~^<{`v5NS`}IaK+#zJvK#ON611e(8nYqg!i4Li{~_ZtUZT79Xu;SG&yf|VyA}y4<4Jp zIj~8bUHpCjq#oTykp?33?OanQgwH@uR(TZ9pTbf1JEdWeEx?=DLLvwv43ODN9KZO3;HD8QR z7fO@)x1g4me%m_yD z{0oRg40Y^4%k>PiO27)@MBzSqYNk0wmWC-{>}1AYcx1|e#}0o5Bv=$Y3lIV#Esk=$ z$RA03grV*H7h60KAEhfdyu`d;3}Kmu=|?Bs#2k3`Y(skLC>}d-jIj~TmMyq+faS0L z=!wX0^sxz5!>#*EuPPyTECM7M^h5Y_FwZwQn6ltOgCaDZ93@Dv^mC(V?F}g2RHjAK7YlT z=U#5&9gIx}k6>~9y$M6lnftMi9{v`~gkSqd2N`_*OFbL6FoT^~b5Jab;Yd#8hE`rx9vK5G=< zx0ZtL_dES-WA3=*p+m62Bd%ptO~2i>VSN8%s_W2HX4!r@*j+lIaxBXZ{;Hld*w$T9 zDP5z-KkPnW!Mp7GfO$R~k7fJ2O)k;xZL6vt?D3;(%$_NM2IHFd&31P<9FEN|GA%?e z&e>WPM(|5lpVxYrCG^mNb4J?l7s&*lg{g@89OH zoW>KnZ{JgaxyP34ah7ZBK44+0Gf)TLb>~?FxZk6S1;i9P4?EAVGFUcs2)(SF`JXE9 zu7ZZgJBw?$gxrye40ouRftJ4OofBX&&!1h}-{FaF!&Rm9A`FOQUGaIJXZ$xHVd}bx zacS<5b=Z-fEJa7Tz7?u7bc#+NNrk?us@AwUo4!Km*4#0F$r66H&o%U1h~dw7-aCY8 zGP5nS(*PC3WUcauEZmdob=o`X!WA3n^t>6z(ZEz!NL_$ccy^B! zDuf;YMilmGngGC*<&ms4a1XIuLnR=XY7N@qIyc*0b2y4HL44WbhdPz^ugWlxb*0l- zGd4#CO>?AHo{=7vcv|qv8T12)eNVIq6`+~d)EK;mQz6c~AWmkvbtQux0(M}Fd$}IA zg|4_086VWhkimm^v1{PPCmUFYf!i%Gy^%0&I<&CB8k1l{dzB(R)*>zN3tHI@rRgd( z-{c-_tQe01RhfHP>JG_Yurh_?21lw_3L1n=C zAja+4A8^6kyASvaRtYmK%bx%@BgOUm`f3L)D5fp;NulSwr5dKf|rswig=Ew{6p0EN%`>i|~cz1aNIDgi?sMou+Xd zr|EhP`zv0+v@A;n;681#7Gtkh=|@mz4T7Mw!sF<&RQ$WjK*aL^s)Ko+r;4Bqf!<=e z8;ctn=VrlpVE}H@a+?ER&k9G7Jq$xlgC+=kF+ERQGnUkYuJ4U8V?+En3Q^iu45oQD z-(Tp*ynqHu9z^$U+{%KJfFcfftasL0y@OwaFkqY@74V}-2OyXx;~X)Q!*v|{7T=D7 zpd5T#HbNzf3MZ(FLEHAzcpb;<)vJp+*h?fLe&wN-WTdUUQTo||zrH>O~(2xMHwAjAKK4QHJ4>s01k?%!tq*Ks}xK5SpIdCa#}Zl;o$TaY@4U z8)K$^>?;q-(sMK7Mbkp~;&XHkm!7RBmyi88_UH5Eav8^dVsnZy4`V?RpTW2|oGXW^ zwQh68m@i|_m>)uon?34q7)Q#UlsV6Wa4Uz$Nla^BF2wPO8-ARuNc@om7%iX?o}RTg z$aT)Jhgc9NtbyxhyK@xEC_`HF>W!?G*& zrvOXBHq+aoJZH~5g}8IM3! zY35&+rw+lGr4(+wxr;c0&^%o)h^jO1HyaMHgfVAPyzI;gZ5~P}4 z*)F+#C8FfNxC^o6q~=$!Kvw+Jxyj|cQ#?}|FUNfjDZ!R?l_xe|2=ZV-xh6lxjfl>2 zh7@eIhKN4loybIF3AExv6yW|9%y{F6#}g4Pezqt*icZ{5AaP1DTf&uu)C6y-7aX}> zTC)Wp4;E-cGLzyhW=IWg6eUoQcfEHgUAZoYM}sJ$N}QzRIf|DS`(;8*j6hbbO1$D{ z=#x{W6u(6K;J3V=bXqKj-YpA-EZmm##A%4int-|p1RrRU32^w!K6X&s(D%^ zX2;(5>H)?s(M=-z&jr6?W#iPrhd!nA@987_FQ$J*K6UNb|6BfwuS-08ubTNr`bYZT zxxMrMng56UzjCkt^oRC8`+58Q|F`e{-M&BK;r*7kc*PpI(VoNqk3v7f|K{MZN|eCq zCI?9{I!S@jOb(J@bdqgh%Z6ZQ%P&sGcnD4v^ufvj+H}E>k1v--|L;94v3d&Oq(AOl zsU^#qBp!>|I(|Rdq=M=E?Zq~yu%`v%z@&%p70>R+JKckSuwD4-t2UgmS`~?0oqH>~ zLy+**fM3*ZA!`S+L0Q*2mq81cO3sJ>P||l?D<#!DR*zVobHTPGlIDG!a93yymtxN= z|DFp|J1qt~6RkepBGAqgKw1+v_`AycSaK5rnEu)?K?#iC2&i?!^vxs6xT)1M$HC26 z{H-a&6P;w0m5x(ZK=&2i^hhYUj8=~q(1}z^2rHWw+723Hdv=QVzgmGjY(oZSDK|&8 zR0!o*z1S_?3G-2eeK0k3{3<4{TTE9)*=P5yrhb^H~S#@5_9Ws$WU- zVB^Nlzb1ZY4eGgB=#@(gw^|Gg%Lw0-0!V^cb1m;yu`foT`M)SXrO0tkB5e|Aw1obs zUuxA(@-6piPTr%x&sV=BY?NKMa-CJ!6`RY<1)-kq-$TKu-KA+vjH%$UDr5DnzBZj2|+3P-p%4rN4w^sFTt1P3gjJOTO(WGu`QjkeRDsPzlUrMU|kwPK|ljx_D9;RGl+$8+fqR(0``ri0S?mEtQ zKf0{snyfji^387WVa*0|J>6)3og=1^_R0Bn*&e|79U$~~<6t3-^aps?SoJb^0P}TM zaj{z``e90pDjFC!{NDM7D%ka7+=sMZmPM7enV7yT?ob_IE*5Eo&*%KalByVU1w8bi zEzeyp1!Y6i`$Wg6x?JCx$bjwSy>x^7MRtnwhEXO)t8~JQYv_Sne65%6PH=HSX55xA zXR>HNx+${uKb~b@8GLj`^bj z3<2;pj%%=vWB!@%A1K5rCgpG^q+XYJtD?!%a6l;)F7j7sR0i#r!S$3?^glI{edKp{ zaR@RM*HJ8ID4h{@^oa1cU>VoZc_KuAt4J~`M`DvX$XWrOsk02U%lIK%jKj;k%-vuT z%$u-r!CCz%nIjQHJ>C*qEd*Y8l8}AkYbw4n-)gY7=#1-Y_H{=BouI*SO$lGfMb&^oWIAEM#$hsg&-l2g<5&~p;|>{svX_os@v zVKyB`=gb_l(ED5v|C^eOxo1o)IL`_vw3d>C$I=HRf54+yCV?`Bgh0g~eGxP!>C^=d z5uhzEVTLRxrooLq5MaebPwB*VX|D=+cG#T(iM;B7ih3!eNC z!p;akoIj#OSr^Q+8N#MR!-yhogAu(N%X&!T+MrnO8DgwOaxK5T4g+Sm*SqwAo0yhSe_#NCAuJJ%=n%3qaA#capzQ%*w8JnI zZ+i%)u;40aVvQ>KPRzlMPxWF- zRL%ufQ|e{M4I7u9GQ-dM4EZ8)jc+{||?jJ*nvG_Xkrh4C*NOfq5 z+}uVMD7}%YeAEuVNz+VN@>3ESneH9gPT_b}iEZYt9fo@vxAZD&!fZ^(ywma13js5+ znVrN5cqmjv`0;zI8ln3YM#MMhT0}Q$>0hl$8Qb`O<& zIsZYZ0092_*MI;30000000000000000000004I<1{ez=t1=}1ifQR}4pKoBUlEU~L zK&}gA(yuRIU~FP#Su1hMOrxQEk{_H8H{3S!ZmNt3jXnHb^?x@cT+CrkevbHXG>(z; zF_BckE$`HZys=hHzXu6sa{yx$7ed+;Z+Bg)S2$4l_a=y9pLf@*IH-)<2rOOMvd{$nh$I)iFRE>SFqp*-nO7(fnUzUFdlN* zI?sMHu);REx6JcBncdf8I&JY$wc0u>JuZBXm_bUQp7WZ{h3XhrY0g!@My<)m`S8Ut z25@-osC(bqqKSCgGaekWtrHtGA@%gF(tfB-)d5dzimd>=9xAuaPgQ`Ay18KX$nMcs zh!%8YF_%_vM^GwPB}CG|Z*J)A0y_)opZwAZ6YXx3Sp84G(z76AH(Y$oEo2$583ict zqaQ>C%7d?_4IA7}G-|>|5utflWE=D5zO3-QbN{U2*itEHFCVkVHNRpNxXK#1e$?Rx zR+G)W5po6utn@QfzRz?X-0WGNzlsB^g$#A3Z!Roiq|(6 z3yyZ)np8{${KIdpkAMl=O?)akg%9b5i~CGnb{*z_giuNL=?xx(0FG1dG$PMCKY|i& z&dCcE^I0YR#+=e~Js?~)+8=pL67#?*N}fFnwTTW*?GEx%CH#U3Mh=H;ReTUhFI1zm zw{vndr2>b7g89D-1=>>?t&E9bn2o<~#FVPdHh6<&VuWZyhpzs-1>&E8!wgB*)ZS%Es$Bx83SzO4DAwYH?+! z3KrHzHomm7_v_l~IoMO-KhQ8pR?_Lt#(txpo`M^Ej0|cX5Ln5g@>JnI8C?}UWq`F5 zri|lIf)|0Wi8*uoKxY;9fcw|p!qK_2`s-3v zy=6O;OU@MrQ8TZg7C6S|u)FQ5O0m(xrjwhABvQ3GfzRPXkw}PjUSdea%D{9E`957H zt(vy?GSJ0!$De!(EAdK}8Zrj8plFdzZME78+oa(-Qr*LfuJXo5=@Sq~86tY2}m?OFXcMpp!^NgLGNr{q|x10~keJH6v(PtuD7`jB3QZUpQ) zR2*d2W5+SUA#)lq1BQionA~+E;V9CV+mC)@VhWL&*cp@xRGs0Lgwzg~ATQD(i-_8} zn+9`97pM7R9sal3xqM$ST7RDcRh!>(G4R61h&_ex!uVe)NQi{2>(u4{9^-gW6{v3^Gbf{M zxu2?j?r0Yp%#5PnLf-b86VpCw8C5EDAnXreudcC$r0Z7nA=B6c4r$jiPtwc@W?^x; zgdRO%$lUXlhoF=;gMa{R(jIz5`pnj%>~!LUboFDVdvJ!JbV&8D{?@tX5;#f=Ou{Y1 ze~A6R$|MXCl|qe34HY31m(hc70M`g&e<87Bj!V<^t2eK#RCt|hg-!rp>LgT$zN&mh z!S14Lb!JhA(Q%HKI+F z0Z0ArQ!R+#lDO(aJ^@5|`E118bUqys5bYJ@xVlLF>iIsYQ<{WX@P1_RvLrx))RlNa z42iHo<$FKW(K8`M1bBTfNzN0P5E~1b7_9=QM{te6 zwCAtk^pPge1X*`TYqm+rwrpH!e&@^WEpg|<3i#8Yp){`&Be|B5Rty4Mv*As`0lQEJ z$2b@^hJ6~3gA{*!pr|p6&03jxrbM3Pd$BHRZ;V~{c7)K9C*(K7a%^*(*gFPGse&EAp-|U;91K$jKa5Xv4gF+{ihaEnsi!Mh0CRsb1FtWF#+~wHKEc4uPq^vZlaBhwyJ^7rj8t)?=le@>2bc)lz#Q|^0N);!^1~qlr~UC;%7nd1#?in}$nCD0HrM3u#>r!g2f$^&Ox9L#j|WP2 zsSg=ZN|&El37$z$q9I}+gbFE{)0fseM-P3t%#sOvWnwxkSLeV7awEs8Bxgf4%t-&9 zs*v3M-a(G^CQx}Z@HoB6D7=Yo*mfy%;Pxe;)T-246kNE&=rLM_HndIGO_sI!;oPWS z8+mXV8oHvgg<{TT&KiAt=jl}N+xKt2x@l%lHKWPvzCGaPhDS<2t z$%8P`8N`>=Em=0Tfgfu9@R@myb-rhlL~*_T&~8VPz5{ZS#1SwCcye|kDuooD)8-rd zaxX;h74N_)D-=%=AbLrxGoqcXzBbt zL~AP0S3~Tm!Lmp=6y@Gcb6EIpnfYm_4vuU4Z%1pmHJVJ5O6|Z!vAJyh`5NZ*i;p@|G)sh zUAU+{j#PpGL=X(L+NIIoiQFr677evhL(ULjrc&3zCKxhnOgn+o;Owc5h9=H1_^NZ3 zIVGfNVA6a&ErEW8E39Xi!zsKkI1UemAdY%}vzs!8~+`LyK8&VC2A8<|IsnFj_FeJ0Ap50UC- zVJ21GyJV?Jjj>Z-)}ph-(ZU!uv`|W10(`&A7rgj&)Q#{b*QfVKVF?QCe0qp~frq|Fn{#?}4BISdk^7 z4`}yP&huvaC?J}_w9V!a$zRLfGLS#?x+i+NfFD*=CK0u#xg~z7{ci^YC!ersV$w>@ z1Z*#}NG0*k*|y?g2G*#G!k`eXY*qHkd^*A_bwbaI>QUmu3aj2~Di+7ASR9KBAsK*ZLd^AkCba1AJzk>GCsfm~RhZSi*q#C4WL0<)z=xFx zN(wo#as_#0BWyV1Pv(zn-gHB13q=;93?PsX&*4T8oO4 zcFm;O$-I_c10&}79AQlYga~}oqbIMjQs(KHMFJgls1Pi$?g{1bZpM)F^aa6?zKtp) zX=J^`EtmBGI$8n)nX&mdySfSihRnA|sM&DBOL#atTKaeIQeO180x9xSG+w2WGWEg= zZPoMbZ({KaPrre6Bch;$fjPCFm?-eqO&H_6rB~p^nK_0v5`Xv(W@TLPP~Ae&NV{R| z!fz9zFJ&+pj#Lto`wiBy>H~{7yVn~Se9LmD_POelOGXfC)#glf7)q(u#9E0+tbcdf z&qsb!nX4@rW?G~*_~v_R49bI8C$JI(1|*BzZDL;!ghwf6 zSbwO!<7IGcl5tWHl>)Mf+BSddPVxN&#ZvgnShkq(aQ?>VG!hd5>$v?-|i%9xRV6@aBo*~xj3;Q}Wcd;zpq4**@b%M;sts&o#2&O)vV zhdEG{RQ}l<_pCaUvJN}`yOrDAkilGAK-I}&=iX<30~GfoNQGwd|LW2dNfDpEd;T@UnT-C3SO=~2#Je14#* zrt%kh&Rtt?Djy^P!hx&n1!M*c-Leo^wqi+|-o4lSO-HPBARUo{>@+&8k>iV$T!W9)Otc)Ep&(0XFmau`t)tr@p+2@vZCt zn6Vh2q?~WuktzM&N4)a#?x%;sJ8lNnDXRm^eT}SRJD5UD2#jf>!}&|05Q_Ea8j_h5 zn=rAZ_JXY)@X~DaSLR;JGV)?}jMzgOf1@%@);>6X3oz_ceieNI*P{Wx4q}6c-Bpvl z?i}R?y}gcpZKM?GU<&JWYG#gBl{sNV6^mELdZzn*Pcd(a_@wS5Jc`;?pz|Wh7Q)H< z14>&Wf^d<9owh7SH69vX6hL1_Vs+CnJB)7w0q99$*=rhN(J<5#e4vrB0#QPtVqv!> zY&40nE*iR=p(r*AJ>Cr4Da1E9cbcFY6`@68B4gNt)aWE0IaFxv95P!mZz2hy9Jk-^xCf zk~)-kr*?r?4-{;TxD#!c=4tjDg5eR`8MYx5?&Z=1pZl}jV-eTb+?c`FEb19#;{5x8 zJkFpdLoSQNA$1!zxicOr7?`C8j=F zj(*j7z(-95Is(~jEf5*lJaoqd`FxB4i9{TxzQI=q@?J<%f)Zf_vCs2?*y&rg~5)~3J`<_j0g(7HiE?>~7i{j|>W z|J`)D(58ahHCYGL+y?EE{+dH*XS$zQp~e@6|~vZwV{|^(tL8w22#dK0?7doP={uN1~Q!(?!FqTn>aSN@EAfe!Bi@lHpL_LKj`T6MI$%iSg zb4L5p9GwGKUTannnAZ4Pv&x_5u*U-m-)3eWL5GN8z9Zo=)}Tw(5OPgyV;HJ(q@hcV zKQ|@)WPN=0k?ZrPOgplVE3J5ph@1F_VI@_u^uG#9)BkIY@QU~W`_tLxr-jX5SJf_9|7l=~M z)Z+@$JR-*I5%a%D_K%*vdr7u)JW$q&OBFn384`Y|j$nY?nopEC}Dz-`@j zM|C6EMJ`2P>8~s*V-qE-Sf2*l?49V0&WVGv7-zGQ1oVr3vsED0Gw;rY=aWWll=4>e z6HiH&hAn&M#HVg6bj)j#4h<&^qTTv;ihzy*kIbIPThN_ewUmGkPM{eh?V(0c^H9C} zsCz#nVQV+pONUl>TQw#cGlM1`(GSu-`?2+4eiP{qB@afOuSF2u%io(G*XA9T`0AHgosfqIvUVxv50qS#QHCoc ztDuwX{A0Q}Y~cVdtD_K%9un_@GnqwMliJK79OxIxN|8cBWt*dcq`p)$%V^dhNlQAR zJ`+Z|n>rLkkC?`NSV%s|s{oD<(vTXhxkp96O`aO#8tO+vx#X{YSmWXr)Y-DM=p4?% zFF=2Zt~5S8of8;_3AaS4+eMvI5`Y$keOphVny>-0CgmM;QWw)?Wi^OQnU#zf|B`}| zyh)>Jh%>PH`ja3$-7*3)sDX2N+w-i5MH83E+7kVM^|-STdx zKOFTe?~q{>aGh|hy3*M~)M_JgB%vy~5}9T>mkbwRGdG-Go@Led zju+(pm~-7Ef&Z-Bp2h?|tV{LQD#_n4(y%RD(F=vE3E#NG!Ti6Thr1mWJV0^%M*#P&lFc z2Q~KY5q_H9S||X_6~kFXnP@zBwZgeK={OEgcA^`EbXb=X0ru#FJmr?+LFCv(>wSc2 zbb=FWNv6PLClpq8zjE_mjNcwJq;W_@gz9=GeK}%6U{}9<<&Ru>q z;gk&lHVLE$N*^V%eG>$a&bQ)a6;J;p#BWdE$+gPtCUb@iS$MW60y!KbhG%{uB6GNI zkH`jkBMvIrGCc#c-{RQxT_AJwMTdKGvy()0KNHZhT4dB$Uf#lVHy7J<{U5pL89r1e z_>Xo9@$Cq5#La?ITg~=ebaW1woMf3dU&LkW`b%>9;=4@JM*W;cmRdO%x8#yxXx9K4 z7^6sdTBs4am-Qy+Foo!pI#7VNyFE?GT2fPNal8Zw97}}(e+M;c(((L|BFk~z^2L9#Qx)}nH z`+-Po2{ws2i*qXOf5>5)nGy=Rvj z%|1F8>UGTJjdiD4JPZ}cm3d$!lwv6Qq@{igo5=0&7An^-J1o*ldRHh?g z8iXAU_K5)_6x{2kR%0M{=ztFAtf=<~wST27Wp!5hf=16~*Eq`}*H+h>W*cbRM2pT! zx85?LuewibS3>Cf8zC;3dEkv5%n%S~s}@-;iYojY?k~P!-vsgT`LexFige>8oX7<- zZRD|Q;>()Np)mA>=(U$<^ie!T!%n{SSZ12g>Yx3 zr@B~m#vqf+0cj0|Et;U(4u!w`<(^&lL8}+G_HKOhX@}2(by9~Np^9s+*UeO7UNO?| z@osn_|C}cVoOUpy78d1OGU+bX3*%ni`p z-MlCZ3Cv%}r@ZHi<*HZL{Vk-LeYEtSY}=omiYVxlY+!dU!As-7o^TAC&JsdCI{QOj z<#_=x=+mJ2Qty8YH?ik!OP8f`GWh9w$r?3I_2$owoBamkv^)g&Nx&YjCLxV$=9ppl zDtc9ka76b>ezuItUK$JZzo-eQ&jNjvU2R?vwB+lqA&-f!Q`7Thjg;E6&P78Vvc{nP z_WshYXFPPCiP)h~fLdcg1BQ!rNnTrdku8ncmNRD6$j`L3T=<$LJ|7e!`7*`foHIU; z99SCl-RfveNd0+s#v!jTz4&3)UcrX<(#%+mRoOjb^fI>Z?z5z>ytl3HH%*aF-2>dYkyINzFs@b}=$UW8cXuja2 zn7LM#%%qfn)rp&)8kw|sgsb8j6{ydNWzr`5|KH-1!y#!ZDrzS5!)w@K(rPVLwSvJ#y%<(diW=EQUs1N4z;fuP19dc+)JpMDRc^T2P{`q9-@} z$0@?ad&V46@RgkT1R&n%Muy%9D6X+U1p)%u{*2nocti~M(XY(4=u9(MIt=rkq(nHYElup}Xw0;znrVmqS(=m=4?v*q9`SvNO+-#Xe} zmqAitW~&{WF6q6xIQeDsAhpNgvU$#`YPO z*Sc(~K>6vCRs5pL5?CoYJIXS)h*f5-v6U_zAXeMi7?;oW_3RWX<^4%^WR7U;yo~qA z73le_);N99I31e-er;?O;2Sn_oVB8S_*Wbhyoar$$-jjURzh@$S#B4CcUt6+Rk>md z)=7hH-Wr)B$-O93m-nqs8oRS90L;!C{d`*=iCgHz4dJt(N998e`^%Di;x~FBQdIg; zCW-O`RpFEh1Em?{M(WKykD$@8lLLv)LO?p6pd@W;(u~8`f;Y@l9l(M;iu%}XD+8tYquK%q1C#4-p9}at-KoY$(nEBS0Us&`o?Nv2`mB@c@B?_*Q>-La@$x)1> z@0p#_@=xUi2-5IFE6cSK*73fFxBK(*6TBXv-2CEJ$URGtxMEkSXSAL-CJ{M`hK3%n z#|;1o|CuBSjM7Ys{h(w*#7$j3fJgs?OGv#TBsFjy{iUEYvO2DhmaEC^TtndN4Rqg{ z-bLsSk@MFNqq*tsd6pR8%VAV$(=CO+Zc|?}WQvZsumUJpOpA<%Pgf_!B(K2pbJE4a zleE6?pY}tMrU@|ng}6UFZ%GNA&5C_JUp;ave}b|Grpyf(Cx0}Qb$3~HQQEh$JnVtv z_C2~DG3vF{i^iq@d9j6>D9BBXm!rGMS)y5z8ABf~&5N}eC|M|tXa$uZoyuN^+<3pu zNrrlg9Zm#t=oKmNb1W;`tu>ib;or-j73=Px$#ynhRa&fWspEJgTPL^OTi!_z9A*V; zU=k+vfmZDI?iE8X-_Dvux?q7g(lCU)6ULWW33irx&#EP57ouhmr7xbJq{fKtk^SfC z4qe?b{7*WtaP~m!Q`b4C9qD$6v}77S7$gT9Y#Jd=43+$22Z&8ibQ!E@*772(2agiC zg!vEQ*g*r2^|AN*;E*Mj^2yB1lG&`jb7;^g<;x7xNxGfQ$5srPe`=iygM}l11B#Dp z=!biK))=maa7lzJ#LH8CdjNFdK~#ZY0+dyY-!1`NBDiCQ@jAfXPQIorG`9(8DF{d; z8wur2M6C23;mBW`sW+$Li}zs9a%h%T-oMl+*#QYxM}-Ec`XBeWhHdZ60_hUNTB*FI z6&P$ZsTZ4#8bTX`5|9M|-3ze{O2j--qjJOTS=_B=30%mevf_{kwOlhLt_)UBU(moz zU4ugcd$}%M6Ka;WIRh}$6JL4BrbUlxIEqJTr9 zwYTNv@JobV#vQshK_=g$H}?xREgFE$z-*#NEUi2x`n8ZgU*7otVZU(=Se|o(cBZDh zcH*_;K2vboG9vKuljTFD#Z?5p5wN$pGQaSQU#|zwwJ#V~!%g{J%_=cOmoG*jlC+9W zT^ENe*enleUdX2zqHKh+tFg4;H)lR!oJZNYni+wj6gOu^kl>Z?OMGmMSfW@^r#OiK=!9NIvpvJ|HudXo2f+PEE^Tnc{0~Ddxn9XOIjcORc=-Pt+uv1Iu;KWKMq|noQUSJWiie1lC`DtPtO*rXP0;NzD%0(H8a#SNhV~!j*wqRpe0uwWrjMtleJ>& zoZv>_H6-bTbOM3(C0u(u0{Bpdkb90fG%2q=uHb9%%A~95$KsIdSp*ORy8MS?Fh40kw!RwqeE0H^P*QLaJWwLS7diL`tQ zdx?$-Bvs{b(@+bX@Ls%b5=_Z$!P1B`8wDBcrL!HcxQFn_&RH3q&lw$6ymeYq(oKDL zCtrXEug4>sdO2DF{LaU(5j2K(ZLYTDrc1k%ObH7jk9dMBKo3FviUdr1JL|{eMi4-k zZvVk`3F?of*HVMj!26l1t z3#lwJ9XZj$a8V9o9j?(}+iA`1UX0xlW*~dz9b6)M)%#uq1oZ%YY%r5)IJu7FwpCzf zc&wN`Irnvt)-El|08g#_cE-Nm)0s`W`3OOJQkRFnHM(i==ia5uMj$`oV8~g(0b_PS z2~d)bbDlK36z8VAdroDQzkCZ<^FwyROb2Jy`A8e8N0BT2MzhW>d2Rp+2 z?M@~k5lK?Hb+Oz60eE3m7e>5fHb;P*Sj=C0)j)G+u_l^H_mY(lC(Ob~;GsYF;+vDPaqd?nr;buD|G=-`eL<+LS5rNwphUV-3Lhkf9gl{J4Sn$|)(L z&rhg0L!bBNBUWl%<*QbC-Q@iKA5mFj6}=M64Lwk9!H%CLD6t>e=bI@)|Nb_~Z_5NZ z+o0yqUZMo;0xaxyi*fkfj;je6>KFJ*2PNu}Nw9w6Lg$qOX{^ z8VY-CF*|LXs}OCf2N5NpY!fDM;GjoLhr9#X8YNPpFBMg6qA#sW4`7Oo7Y|zCKrs_6 z;2OwP9DdOemG0NfhT{nC`h~4)QG>3|MbOR#q=$qYp z3)>&gF}}T6HVyVjT|7<-kALUc=tEx`#WQd@=dqOi-JgK6HG>b9y<|lQmlzYK`s9&T z{nM=3BX1n^0TLo-O=>>q_YUa6aDNt3;-WaGPq@b_#*11YFxfCayoVb;%UAg`fAx9j%kidT6 zMUche%2&yJ>GNx22r_q&B}o70EP}k{Xc)Z!$^yUP6=IefH&~52WaOCDE=s06!QvhE z3bx`h#tzklTmmd7@{|t_@FrDv^&`+Hzuc0b(qA(?EsqHd2)w#!5lE4AL9J3= zS9qZyPNK84jfah&Y_oelz!7#Q4$sqKrKB+mSz*>ONAb%vxWhxW5`6pJOX-P@1TpU| zXnU=uXzw_Ui@Pu}3WW-+0@*8mvJZM5o+Nj=nO&yrYfr9iBOK=nY~kFjC4_kV+!R9` zzRjZjN_g%S!Y@za5fY#xpZ%GDtOnW1`7MuY@A?N|zW-j|0N%Ok z=FLO>cgl9pj6|Or%G=Fe`u-{pGiCYtZ0ljh0@At$sO}#`e#qJ@gn8I9cTfRHUv6JH z6p<$=@~vwQX7Fdb3bvKE_3Y@6)Z+;9BVLgFu}*O3sVS)v)m9XJV&e3^D^?wRR>#Yl zVm!*@cU4^p0>b?nmV3;0Stz|%bdS8`cc{P+ri^bm1%abpNG)=q!V&uwT3)bDg%VHz zDq0-Msl7z(eN7p}MMVMe zX_z#UzV9Fr!`ROiB(!w6+Z2GLNbi3{7+f00$3<$Yp((Q2wII$_L7qv5qC@f5G#6LJP6etqEPMaqn9u0&p5-b9KD$;4sk}PwJ8}nI}Nh)T~Hc2FwHjkXl`^U9< z3`(C?n_UNg)PZpga{u&@;pPwi#?vAV`@N<;KN|d!F|KM*Lp;AqIx{An-Y;QkTP_#M zi(H^=Obq=F#9JtAd6?p>fKf#$M)(|ku&qXjwX4nV17{Q_B+WJl`v=uK@O!sucWzP5 z-tm?w?;A}U%u_`~s8~ZUkFl{pb;MN^EahG6YZ-BEQ48AACbb1-EY4p?e>1pz`syEL z22JKNu8Z~*tYR+8t%RHmhgX_wa;`!U7QkEkdKIhsyuoio=DQm3(t6thB`u8t+(5$D zz4u!H*5)NJnQKAD(WkG6b6^DS4;UGe9_P_R1J;iT5UF^(OMz#d45c>dI+$PS{>!{g zczvh(nTqw2Ku7;xiG<~+f%CTjUX)E!x64YO{(fKio1@cYSBVF9&RM*pE$6sbs;`HL zEt0u!P&{+c=OF%+*oUyX8XvYuV3&j3^w~cfCjEy$XHCmX)u3N@ec@%db6y(Vww&!M zXmjl;ragb^3QvN#k8?%eciwKQq0-Kwv5Z!Mo0JXOfh4SY@OSaP5H3T-tGJDj3R_V)$Jf z1PrZ#p*&JaZ@Z8e;*@XsXTGi@+A7BDIwrl5Dv(hTTeX6BNg=!Ii-(~uuf^#s_c9;@ zl=7mLYKB|$Y9=7Q0VAW!$^M#pvSpZzYF?R~$4OH_OYNix+{82^g{;J=AVN6^G>!F( z7_wD}n8!-ftFqzMWkXVnLxXfuqX|7b;pEcDox!1t2*$m~7Efs`D856@Gcl|M1eNcx z1YvUBKZgCG!J^Zb@MvB~+06m%z7_dY)osc9!Ai4}QtgU#bevCaxG!1K_Iz{DF4yPX z%JNN8+RbxUQ%kl-xGrBdPO{|?_MMXDW`feBikIUF!pSnd^0=s{;r?PGtx+d4HD)kx zBj6OH%gz^u$R}csW}^eL0+~;%IGmNvHDFVd44-`0v$^kcPAM&l2{D6T*pbD$2v|HY z@jr|K`=F@bl#LVm?hj&ls#Rf_Prxm^UMK{xzOool&y-?D26e=*6q<_7cqnd?-qXpK z^pV+{t&+UlDN()JXYXf2bihv*z%bVSr{%+phC>7^?#0Q^|FMp-N_H4_fjC zn}t8R(} zwCb6Q8Va4j8$CvgZ7!pzs&wV@u$-l)P4@N&jeazq$1fIz1=1ARA$qoVw2#g@mfxr;-;vy*xtCg{pIu^(H*GGGi zjhn_p%4mKnHh7IPtm4|AufO8^j?brKu5%o>jpRrw)#jh{^vrqljED&UWM6KNdUC8T zz#!frlGPPe3J#L6w*m^t{^$jJ;|&$sY8J+%K$f;ZTUbVbgmGwV2eLwv476=Zw;Pf; zkhSNI=%PTktQk-p)V2b;FpQvRTSe_jZUIWRA|U%VH_ENKS%sopBe!$_nYd{L1?~n3 zr{M-}z5-`|Pkqq;y>c2^YD*o2Z~$esvT!Sd>dt~B3k6UD5td*N#%Y5y+PZ%W1lU|= zHYXeGDl4F5D|_=_H#zJihe@8zi6G=KW~b^pEFc)UN`3mA_x-)U_tyuj>T=F|`gBM1 z-vcCDk|arzM4#D3R4x@WcV*?{^XEe~BLO5wk|fCuq@gl6G@*+4(x?{(+g;r~KopNO z%lt(29}Xi)ilo@7J_hq)?gmVK*tS1X8(FlQ?gk{SBr*u_*t=JgN7`h;lC1GbBIvA= zg#xmWKm>Vn^7wc>@*=PeO2l(*b8;|obB@R;ki>YbU<(;>a`-#v1oivE@AoUbe|A-O zRYmll0&S~xTj|PvcKnNyCIlfsNNH!*(s%#=ptrx(H~AE9xNw_9XG9OgY@Jq zI17tKX>5OapIkDK#WW_8dp=%t7w{yeLh;v8$o5K2q}z(2koyJ*$M@b_dh)JcFq5A` z_)Z>y^c+r*v|qTd-L!5TB!(Gn#^S=q!2#nipv*DC{lsgWxXX!YGA0nYgKhWWklrv4 zI7p9i?G!NrDne=(8mg4@6o0io;iyp+Hez>wwrn^!d zcU=Y-)K_R*yr_TAIY~GquMGumvi8M-<44#+_;Typ2DtAE{nv00eFy>Ke&G*mmQ56K z##&(?DHI#VEf!v@wj-iQ5h0S{eMLr^21+luM)IK-OIA4sw$DdoVOl6CCmd|)I8K_v z;_{M%;msNPJWW?osv*oUB@}9t7EA|thAy(rX*&v*8i;0RPb>$MXbOw|se~~Rvaon!@PuJeM(3N83@&#OlF{vK*8Mi{B%*M^@;ZtNeqX%5u$_Fn8TKZQV#FB zV|k0rcchS{Ms4v_f@)ssOE6WGUwN5=r6Tf=I(udQ(|Zill3|a4?^M&}AJO`U%W2|z z7;CMR)bCKGGbu(?EwG0z7vns*4#y3Z7-oFmU%Er7+9Yt95`BtOu9Fm_Q4!AZB?|84 zQRjRkVOhzcE=iBT-ANT$j~pg#nX;^*M_TQIg%5w;svD2CKe~iY;^n$Dl`X~vWk&?= z6AU6L$o`gU5=J>C_dX>pXuHdoMZRM0RidzLo`h#9^K@NBsj8bA_Q=Q;owPwqvQA;r z0zTZUdL>ml`IeVOsLO5_i-mops)b6ToZ3%mshad=m;)J;8WLzr*CEP3dN_i|snUng zGAtvySq19KF3sVg4=)LZt5~vPlcRet)p9+<>lvtMRcRr{^^?v609=j1Jd8i-Dk7BR z=V|yZO>gTu{=sshXxGvyA;}kviWak!QZW~$4EdCDCJl-uoV_BdJGKer5JBLga?Vgu zh&$ORYS7}z{4zdW`jiL{MSf+k&VHg8(sIL*ungKbevrscUc|}8!j$IA7>Xn7#kp@~ z6J$M(LK5bU3UGCgqFtmC#Wa?+IU?RprH8cedgN88qDzaFBcZvIiwr4*6~!T(av{#9 zk0jA4-_S{l(UwE8h1g^X_zM_C%S4d^Vrf<9IP4p~0UB8Q=wZCeO(|$9g4~E;FBZI; z2ElmX;w72oQ!&b8!omvR2jO|@r5J9AUZ$59eb^yf)q`=1nzy+OOy`h&NYNXaWO%e! z=^FAOA?IcUSQPX^B}-W}a#aZtQ68vQk6bwv2OMUpdJGlx`i7-X=O+P_c|_bhfjJVR zW^Mw)T`G>~-TrsnL{NSP!)M^V%FxXYB=13cBPl|{#-%O=#=V!M=9gk{#H1Du0WS|X z7IPulni|v-yuP%>G6038z!j>zU>889HfP4P57@IpWlgFh@w}@sYbL#tmA+3jp=0OG zr2-tQrIGBw!JK<@IGUjvg+vt!fcKyii#dggPw|k8-zYcK$yb$ZqErZhaEhJ=xe zMJN!wOq3UlLsw%?yLi`%d30Wr5y_iavh*JHRjOC=3$In6Fgh5CJ%|8bxD0criej6U zDiRP@0H1xChC)jelFBH#3%b>eZK!6kiv;0AIdOAlPr^@eip0LWUBhCJtXbwWesFjN z)H(+TS6G@rfd5(~OZOw7(1o>NbV%~k#F-!yXCWx;2syC;LL~n&WGiY3EJH-WO|Tin zWvwfpdOV7Qkj|>jG2IX2Xa#; zF1ZJO3Q#)?xEo1RC&g%{y_UfoKmn%b$o_(&pUS}eaw2HJO!QzH(odB1dL_mGgTv^T zYC!WMA46bta48aNT0H4i7{K5wS3-}Yy^_~~nS~@4l)A$l$&2mD^cophM5F@AfS^hn#@Cd_A+2%%X=peH znC>l#KZI0ATDmK~Z1d)T`3b*H!+r?@sv-y8J8UEmm1E|*@QBquJ#698OzmH0wZzBf=r9<2|h)FP-~>p0I46AiMiKNFtUxko5+)J z?}|6xj~Pq&MaJ~#5>56J_#am!-kFj{!?x!tdT~iaV=)4;sfCGz7K!AXXcV+z+1K046i&(K53?yw|17ElCt}pG-NXI2DyLkRPU_;&J9^ORMDTi3iKkqLX6SFO&oNj0pM-a~dU-uw)q8)NK~CC3|YQNZ_^{KMrE za4jH`aebDOag<-~1mnEyTvlQw*aq+v+!l)*8<3VCk`b^(GywG@P7g_lZFQ7H#-ygq zQu+r^9F}USYH#AGFxaJ!H6xIeYtfcaFE?*s_J*WQmOO7pPBqcYu__Pk17v}Y$5c6< zB){l;`EEByQZGSMLwD*07o{T2A}<-RUm&}5t1m=HR5tJ8TZs}p6}%$P1=&GGH1BZ+ zAzK1$1V)%DM?vaK;0?~7FilP`LsLVQdW?m{F>`YT908aUeF;{|k`$D4L@J^{$s~ny z(H6LC_1qPRbKw^raTyx+c(W>{X}#wmeWYk=D5%GEfjnTuRe{lP>!uFhjFQ+zuS=2? zG{V$MNN?k!RNb{q?o7ltTG*lymslC4X%LkxvelK3NJ4{wm!qknDLrni6=)^ch#dmC zuE&OGiTw$SRj7fnE#$ZW6VuCecZ82+;aPqa;vdv9rG)P>Kw1X!`Nj(0t(Ai*120Ka zLk+s&MZ0jLqX+~dFwj+)rjuS+;5gEvPpT?TzBCVem~+dyg&Rz`p} zO(G{eiNY(M3_WE>3Nnnn9Q_Q~smqNNQTVSLv9wE^(s6V}LTMpgFKPm3O03-CFk4Ky zRD;wc{!VYTafvQj=OBWretjaxQ9+9|p7|=$UuEJWE&<{DyucC<^KwvV{uU zA=?&;+U)AdNkzMy1*%EBWgM$U^rWa91_~ruDZdkt!k<0N%)X}DJA8Pt^qCN-Er8@w zyA2XAQ55?S*FAU+fJU)X%D#sf@l?D6WJ)CF7Qu^U2?mE&!J-T&CDOD!cEGUC{7^k+ zefJUj;^3_}kJVRa?o84b*Zty51tB?c%z&s^@5pAw5LxWgX=D$?oDgtI3tJ2(kLZqt z>xClq-vM&-b8aFi&*4`e7OXhD#Ml>cyrs9rXHUyaXQJm?T32ts`JkzG->#zLP9z=* zYJ#OEVQmf~A#hy`?aUTIFF2^|5ju`-I|%C?^V$yEo(o!`DE2KtK`G&~wOK|p>)+GK zP8noeFvcqmj*CRXcb`O=fS*q&x_KR0NX+OZ>;5lV?cZ~!m8E9qOthu-!s=aX;r%S} zSerwF&NODkD@em+Net7B;Y3+es+&1+9*Iq&_=T&R_SWXkFCr%RIwveB50G^d&j(2{ zqQ*H->P8Z#T|ikH$>xYF<^;yN{NQF)qdXkZc`>HH{Z6uYtU}U!_Ou?UQT!p+busD{ zp$=mlTiERjIi!-&YXd(2Z1B@X!IyO|Z)m6)w6*cn1txZ2QLf`i3ML&O$>T^d8Wqv} z-<9TmlJyz@hm<>ulPLygION+&Ggp@8Wj>5Is`b3<)Cy<%YzYBny3CI!A;22)3Sq>U z8v}xR8ezb&P`hIn^ndQ^{r6rLwQu3$`Yf+*CiPV&(DYI93T{pe-$b!fM3-W;)e?^T zZe)~c&IOkHUA2Xg;&}p&#r+wTb6ZbhTo% zg^gvc06dL`nU@=c+8sS_m^160`Nh=>ao~NnRd&cYj`=B@-BB!*W5nWhuYkS(Uu*=M_~-LqUc#L#YU(!wj^* zQ#BqgyAV?bdXNaGlU!V=e5_`pWBcK&8h-fqW)!7|0$aoEOw!vD9fdkM~Oz5l$sCPVgferRw zQT<2UX^@4*hKTH2DDFf<cJnGaw`ejel!w-`yyC4JV>Mp*qzi1K!8qjIqHDHDfZd@0D;$#2y6Gxw8KPtV z^3(m{DifeA+^^8cZth3Obc+xfqR#eq8rEkLUSU8WfY1jHFO*!8@*thMLn4 zu=m`YCbM0r)bBWxER7WkGde7w6{G42+qIa;1jGLkJAAvC0;`20O?4@74&uQF5s-Se z6a{hF+5lj?qwuhHOnRYQ3>GRK@Yjv25v!s$ zV9`rs%x;e~Hby%{2r_CMhL@$?x;P?f07tXlNlbdyuY z>-YnJv>Qz92graeX5Av9`;wU##r$y<3%^W4C6jI8+=Cj0LXx9F@1nm;6Ru#&TTZ*< zP+U{G>;*c-DB5TU&!wjZIGJO++fv@2HRmeRwT0DyIwS~&123-;Lrf`ji)Ku@7;SUP zT!KOGDB67bf)5CKRF`!PY@&;_@Ljqkm5cpsjPd2L2g6E6ymWdYBTh^}w4utPevl_7 zg|kuNlKD1FT>^eR+{YN&`M=SK1yDO!m$^C5wsnZ}31X#$=aoFoMh6GJj82P5L|QJY zWz-%jJCNn!({pqg*u$B)>M8s9GLxzTw$|uECB=xM3WJHFRAolV6-wj+i0U`xq~G9P z*P}6+^rf31D-GR7*VHAsghOZRvrvuMQy#i%DNM8d#!IoCh&qK%rtD%Uq zosB&xBqtj108RWrtR_|SCh8>1puBnpRe!PMU)Xvz9U$A~#@LEk~!O95&0N z3wgQ)Kx{X5MRy&nFQY1i(PNoWfN0)@vavJB&imO)i)puMjYMIDmbGtk64>duY*D zT{ss*=#bDB6?T-*X|dLA{1~&!^YwTXL9uV`XE$+9u1U}eYhKjQqNJ}2E@-IbG&&xo z1Tq}1ly}$!d`4c);w3<4_3A1D+?T{@BR=NaQ24y)aPZ{3dM$xU@GTN*Tk@3SalsMF z)0?;`*CiNh*)p!BrPo!k(4kY`?O^5a2jOr6#Y>Qs>%0Znj2RO%YGRqa zIEOF3{W=C>z9=z`eGAH+22`PpOt&GoKsR^yi#$U4+}m9D@MW zl%&l|BIf@qwkT+fFuPc@Dqe+1zTB2a@wpiUGm2oj(c;31YITq1(<*+8L0kx{>;`7DoQNqQi5 zo?i)|dI5OY(EOST|26;$CZ(qJ_!5BPcL!ATkm)6L@y-&-186RoV7)i0^e((OzHhp9hPVG?+I=47KoLl$d>HaxXg%V zd{t7`#i>oX~>jo;aC z+qrYBmH2@K)kr#XTJp7u>C0%YDTw{p4S;ll&bTF+c|)FCgQd|zf#z|%R{%qYQaviz zBNek?G4WqWBxrt=I(K53Q&C3zjM{?vMFR(3iZc?+JFsG0PE|Ql3W*%LhsQ9y#iop3 zVN6Tex(pXot3)z&k?v-wI>8jlJIAVs%+g7*7Iyxwz~lcnehDUDY$~||Zn3BvwaMff zMU09IYdfVt$tkXiKC+)YT^T1TDE&nW99YOmbm>k!HrHMOs>=m23UhD2U}!o_eSr2Q ze}b*YZSS_k{T>;$TtR#ckr{k`J;a?6*W!+tl(Vznu|~M9J|P1H+6mK%hzx0qj}=a8 z1U`dRqoR-$5^D<}yPK&wYNte!YnMDw6bUsV8ybPh%FEmUCzdj_V4lty@Id0I%8_l2 z+L#5Z{6}6;h@^U)lToHd2T0L}zrp2Rf(XLLMX1NKFe8=z*I*GMDC+?&psnE3+$L}? z!J?7`bC>VodttM?nLDI8RI!8yCshLEDRrLMr??7=U^7n-G0u_G1{{`#sb=b&8fKBU zGmpCO4&eIBE?VLXGCUeaIqu6dh7!hfFI0|Wda+=51;|iI4F1fXkc2Y48X)2bs3;}D z%u8tL0#?1VfT9WX&dXS&DIy2N=^Ns-fIPertVFU>t;^5xp%Lj4{gV?h66dgHm1i{f zg-kN}3Lxep8XaJlGIqYKB^yZ=$;a@+gG%Pft3bR$$XUb@&s1x^Am^4wwOOs6&0oBK zM+9nEnRZWDXNMBHl8x@{!ek0L;scAv?{`&{>(+tT<{Vk5A}*co5F?`xH`lBu5WeSB zb3NGuns9oVgL-2`;+(lIge8w2ohBl#}GN`(y{e zHS=5RqPAPDlB?j>9Y9>nX3qAT{4(7;w+F{ z!*hu;ZMec4F3oW28(Q(aK!+gqXX_K=;iPR#c0O_$^#oqz2|2~eigrG6L1YW&@%lHb z=AJVr-s=pnw*oZ@HqhzlI9~Gg&jEK*rV|b#)`FImGJEW{8>gd=YH3WCDP$UZD0r?k zNlE6)BEl8U`-(9zgDF=UV6o^mYIA@COkd??35$G%T7=X;Y>XmaLe~IRk_e*O`!iyB z`3~27I9VK@1Vi`3>6_>BeEQ&`5f{oEs?ry{)pN}TD#XYo4K8sG7OXf%HzecwMt#bD zf~Ev?H@EHZGWuRz>Ell?^6MOd87llYK1}_JkHr++Bn0es%cC3P*f=6B5_rBGKnTgV zNfM?wVMe+f=`HWjhFv;yTA0p)5`|X!RcMij+@;Nd*+t=T4C>r1!ucgu_Uo!0aWp-W z>`<`-SNgbo5!yO%+9Fi=Wd9urE(efHQ5(3AM>n5|>jf|6qAy-?_C9qaOw|E7B>xXomR%f|6!e$NWqpwUw|$fEM#>5;s=BH>xJ!e z%!~ew7JPC+6K*skkWVu@Dj*@llM_lPZLNmV)S-7NS&yp{ahqyqme zcu^WMgrc1sDaG8hVy@|~R1?A+!d2`#|L`!QGn|fm4eZk6vex*Xbhz5s`a;Kp>bZg=dzVStSzOgA-%!TIiuAEj&$+?R02CNnnA~uY4q6>y9{zVXyV_wT zAAf@!l(1EXT{-pY0^ZXuepm|I(D+fC74GImGmV4H_B(PH5nv&s@1ez#mflL9+Lzlo zfQZCbAG95CL>m?yyaR9QJ;JmRel=Bq=CyIp!wUH}|no24tZ? z{xzy;AZMliUMOQ@QB8u=m2wIb_i}LGA@}2PFkA7sjXEbuT9&hRWk&JKE!RL~&J7-$ zH5Rv9Sm;Jc%P=rFI+O?m4n=J9Ams+L-N6Yy{%(k@w6I&@m${GhIUtT52>UWAt4WWX z?LhO08TDkgdrscM+sfg+<>C60P;wmcF1Vw*sq6k7$Z5eoDc6qq)xQVsrXHOFGe05< z4JgQtV{>Jgpuh$XTnA2)B79wX0XUSU`agKVZ2v4jfx&8 zL!KDZ+(+7#xVQuVy+F52y9PM)AS=3lwrwf7$3~YR|6}*>frKSMm=Re#;s%)IwP3C! z4jvnC-m})mT%a!$E>@Gc`!Ax8Jo`5i3>))&vha5(LIrO)HZ;NutKs3eRDD+&3$I-B z3;pBbNBQ!1F3Q@@y+11VeriYQOkJZDi^g;2X@LQ_x32$h-mXg0$3^UemwQq+AIJXP zj#cBqA8=kI_Y`xXx%+`;( z?!9vLmmFf1?OvnHz)<|-IuZ)>=Qy1;r=q!p77?;C4CINLC8I^LG#oVMIEM8s+Dzk$ zLPj@tww3qAhgdcSLz1%3c+e8;MU!_*j#44ptDCYby9_Ycu%GAZ-?U9c(L3iexGJhs zOSC>{mdBtJqOqPpWfnnsNN*+v4Oj|aWvQG#{MZZ|A5WEmAEGuZc<=@%4O-Pi1|%-O zo?ZlMO62DRsqokEost_xJ#S#)5qHFnKgtp(Gzax*?wz~$TF`N^eCC~mB7}g(tFDS_&RHp)!Ae3LDf;#9i2wx$m9?ujz zTci4Nf#ZMR&zMsZ!}z0NSQactHpAfXU5_l>GT;D$lr#J}FvoDIN8We+NwTsla?q0e z6%RdBFuedi=-8nEHO1}ByInh)GeHz9uub-Di!m7bechemrrxSCe5d~Uvcb1loTGC1 z_7Q2S@fqZWr^w4Q2dJFqB}2s{_t7Wh=vY3Xby3}U%530e1FO#Rl8kTZPMMGyML0-} z*=<(hQGGeH%uzm+{_vYWTa-`I;CN=`+`TEI?4MRK@n(KV5=spe1VIt7jP56Y=PJ_q7YR7;oIB-I@NQpQs6 zNItGa2UG#uq=T6ODV#)uivFVlC#BVm-cef|}(+VXWMohm!*V1T1(f(Kaa4n!@^8-~aYCYcB+t?&K~Jx8!!|L?IX ziTGcaCW`Q{Eo?qMRHvkZ8An4z(J*DXU=xsYu^Fys+~re5FsAKv5DfbnXf{!MlF4BCPlW%mp8qXFD48)2j3|s*@c=P9Y!hYzS;<@kuRRfxxso?Is@O6Z zav0ce-cVMhPkg zXfyjwn>Z@;889P56~r$;N?ldP#Yv0AL|+4@MZ=lX7ttl*JCVw20j}L-<{o6ySqI3| zl1(LQx=put(I$i*X7wBP4E|4Yh7J)~F`&XWFUHS9orVh<%n9buInv!Mu1$uv0R>Nr z=m1FXfH~80lbIu+-??}*A`!-g;FK&(8^5$*EzFFBH$|EzVu;p{7}3V)%*Cmgy$z%~ za@AoAx85Ha{ukC>Wc)Yn zb}VS=KNa%JjQ@o#ZoX%7*Ala*PYQU05LiSYJ#Jk4WXtw_`@!|`o;A895@Q@=6ViQS z^lTlvZXT)GuI*j4S;751a!C<78_|i2|BcS_z-El6&27akXKqZL6)NAnO&Sv~M)ar$ zjo02{EVm(CpU5>fiqG2g=unDbj(O3wC6kES(zdc~QYq8o@>L2L& zV0$jhh>B)x4oKT!d|Jg2$z`EkBXWQf5{h$wre$MR<3GGB2|EfB(;Q0#k)w ze@~I3P2HsMc0ndvv3|sq-)-Jpd)dG3D0Pe028?mFO)QReHs0DJ2uk>SyCP)f(X6r= zvYOxw8yhn-((#)=%SV&r+S^6SYd$jp)+!x5w`Exr*oK;XG*Xru%(dL>z~&v&)2X#P zv|rA*qbvHe4F%Bnz~ZM{DQnE9$u&7&evyCuTQ_lP^IVzy(YeBHqn_l>*;-JfwBnt4 zSQXr!JUsp6-?jd0yC$!Tf0gfJ%&I8eVQ)}DS)+WhU70)1gFMZ`;?JEGEzesyasEfh zQ@}G zj(ibw)V_wQLGP;gmaYHwit`ntIG@E!b62}*UD?MguTHOGAMVS1<@2u~B+)XkO3jRR z4QR!)3Qgd(FI+&eU(F$x(=~tJftoMB0+ui4seKM<D zi7P@r-$v|{{VV_9XDsV&SB$(ys~a5ndko}@@~)d8b!T6)O#Ibbv%9Bkb4hG}YpRJn z!xbl=zvd^D;Y@S6_O;^nSLamIU6B09!un>%v85Qyu}6UxNl z#WDB=(MdV?$w?*jHb9(5&?{+4JgGLiwUbGOqZgWzYvX^FI~0BUw(7hbxeQD!FL_1GgN|cEp(L9^_-@|q-pwLHPJEISlSg}GhScr z5-Im(gb2waoplCq_t6vG{OZnn@*E1oXIF|I&yM&57+1)fWkj&^Z zQtl{tvumY94=|>FC9xq`oDL#FZBJ{-*yzYPZix+BQ?+sr;No-fxDpPRuRfWJ`;P~Q zTWWD?wH+ifx&q0}8Y7*h7n{1fP{>5G{N&c_#5VvojE=R)TZZa;?JER)HYnj=>h8Pb z#p-b&*Qg5UwstjLv81KKBc9TF@5FK!5^1ZDn}Nci(R08uK2hV9c0UFwRq{zq=$)Q0 zT*^ZqD}F4u1i|waydxW}kxJ)sUl$(foRygJ^r4Y+0%UZoP|B6buTb!+l!a3HTQ1(M zJc7l32KNqS)B16w(>O-LD{|_i#^33BIv7wkBmJnDh5D|cBnML=(Q&Vfr-Y|RhQhl#Nun~>YDyl; z8_0QA3G;nMvG_V;uS1>nVcl+PF+tbD1vn6p*I&Ve2Fym*nayRyR3sW zT(?KIQIbR6l7`d*jh+$Cl{$&C!^a}8Gddn0-muTIcCKtMi`(Ni=*AM6Hs0|C7F
57ST6tjNNzn$nPe z;oSGAOoodu?2YDLsIb3x8`o zCEMyKae&uSyr|m3?q=zLzqczPkLxViiguS6vuA;PfXj@bcRgRB;$9`K48i*NMY%UA z$zZ$41S1KIR`}4fZ6wc2R3=%22KpxUkULXXOUCwCmt?X$ksYHXyA|N+#s-nI2N$o% zi+%r{LYv)b2DggLJQ8CTVD~PsCp0BZ4mzr6=MV_BN|%b;M3;QB+>u2|zHQDB_cL}N zcUy5$CiCAO@RR6`bdCv~Mk-JnZOnMfw( ze;_a1m+Zj3b1g0oNIfSt$T=F7g&!7Rwsl%8>f_lXy&LMkTe*ERYUq`*VDgB==qQQJ zQCsJJNqKO#TT&7>DfZ`E$E7~uOH|Cu%t`_|8QbLG_l!7cqBAUnZgeALBc3BkN_cRj zhQ1cBll@1BMESG?a#fV<;ZpKoq`HxeCpA`3Qrl{bb7Ks(%4FyjR2P!_Z}JjWNk1(^ z$nra8Lu~>QjeXd7bY0pd>KobiJKR-Z_wf22VRDcfu*2IJMr73W9#1kfihP-MR)*KxNIl`BS-z~G?QyWAR#TrKbS~9TcO)76{ z6k%gX+M_D*;`4?Dw(PZxcPD0BS@F*iu}{g($U7wMdwKC2BFs12K}m-9ae<;jmpf<_ z7f+@UPU9fFC2CY1S<79LyD5xGh(mQ-cI?{_mSRgyX6;IbD>~;afQ(n+Wfvwgm7-#i z>)`#H_@h5H*CFTA;3&XF)E#0J#M)4f z1}TVG%-_E36WoS(*!SfYpm`)F^&PBN?nw1rI5Fot%niu(yi<>2|SX95(RQAs8Ra z7=+l#dFzt|QY*g-OAfn*xhTPJZ$hr!LHVn;5|C5@zN!OTvg_E3*thNv_iYT02~+R$ z-?wB`A^ZvKwgr_fb6}rAvMHi~!~~AGdjm+@LgNs&u{Or|j>*Albo>iUr=>`*!H$ab zavMB<mn}G>!$HXBK}O;r(&g2 zbvkGXY0{5oA{F4C_Tmw@v0;#RW(50E^sNh$qM(^0(Ksj=Z;rmw5Puy4?x!0V;=Ai< zjHM)BeuYdv3rdb37t+Vw6mp>oKUsBRf3sZaHuBA1M;Icltlyb|q&&ML>wxbPXbxL+ zW<#Lxe^Eg*wcRw3u%`v5oq!t`i*s9yO5?luXev5tbZm~DpbV#y3$4= zC(ECy(xop4=tnPbjh4a%BHk9<-vIaS)e)X%Y5>t=902^t8?YQ9lG_;2dKyl!1pe+K zYYjqf!sL(suBDO}O#ss80~Lk}YAEEo zteDBMRnPH;9Pnm<_Dt1TvAFl5I#|H*E4xTHyn1_wV5-kYqv z{q#YTQ@QvL|K$hYJZgEwVRD>ocy^w|_SXP4;hE*JLYaBFo(ZX_;n5u50!rB$v#Hp_qmr4D2 zo+;ws!K_}^SLxmVLq7OTaOaa<4@+MA5KkQ#egqUql*(uU=TBl4N=>O9Y$jH-~A1}J}hV3ijGahP8s{*x_&r4Y+m;yFI38c=&NhaHc|ihMnGY$F$T zP?bfEqNvO!}~oaPHPbpy2MztNe*9;k6x*!L#~xa(W>0>77{5-kS% z_A0D#0I2b3U;l{q9J->22xR~xQz7bBO%gswIzcfu(`s&rB09aGc!tgimkux2f{Qr5 zqB?_3rXbL1khx5w^{)R>?<=~j;Yd6vBQm#~nH?Bxm~c^q5`MBL*h~tQaqn-$K>Tq7 zvmo}PTaPGR2i>Q*i_i@GF{mN>1lx+8oR-FYYXt?06A%A&D!mHF)LaBKPd^kHG6+2; z&O`Dz*M;%5?mMj?t_)MHcn-y+e-gzq_G=oqJMJ0n*gI50M4zkdb=*TwI1ScL&Lt3W zTl)+r1KLU6lA)27EMk zr%+iW2S)wi-}CEW`?Sjv=ylKt`R2G>g|{L{pYlA}m;x*6y?V%GpqnN-AtS_^Z3s4n zxOU5Qu#!RUfV(hS}s@G@;&V4(kXG6PeK@)GIyB4jR^_uT0l=Xw-*YW^pK*6 z*enA@KN8o#mv3bkuLF4C;~JENjtYg-nG~XEED?H9pfpW{z119<99*Uery7p>b2u0Y z^1ShmaphR1pd*W+cFXlL&?q6^+0i>-!(JCkz!5);>x^Pv0<_1IW8VO}FQEE+eQA z=h9=zAfdU$whKg6Kpqvms=6M;?M^H7QVIC&X_B-?~+uR)? zzi0#QOOnctC9O|6Mwbgu()pT+hz|;E?js4`nTQol2o`kS2NA?b`KDaYnHSYNa_OduZ zOxEY`Y)*l9#Pj4a25o@6sUXt$&$+#c2uxsuBcm&{!Qqg4gomtlvJG4gOM{BcAcfwu zAA0uW7uYt#w#iAV6aCUw&W~&By0z{QXWRjD=^F&kZq9R80T8OkxYx)L#c+RPDn}J>8PfCBD2e^^U!f- zoMCK4;+=>oZh9R1HjV#$6Ly^OIScR_B%oUDS&Mmf@%3??TV6cZ` z+vDx$(8(qtF`RLQQm!3W03t}EMQ)4ZwS)xHs$ewrFvVQV?TFm4{?NQyZ|SJ^UpFcc zC3OxYMBKSA)5^hqfO$}^vUQrYpH_0pJwTy%e956r$;lRu^z;Y^ofvVvRq^hIS8z4t zTq>Wi%l7ODF}&oalsshd7)-0=Q0;(Q=+4!CZC^6sU*zpRh4#(m^ z1w)M?Y?%$C^S%KeJJ_ih=1HuiA@r-q+}&`F)M_l48B)#^k%mVTmURb#=4I`FJO%{pR|_F*W0XM*i5Zuacq$!p5)NF7R*#Co>N;1k|62XJ1(l2ZKo4h(ojB zGEQoyG7NrFKUC0lpgjP?I6gM`IgGRNkcW+}6A*sD7a4N4UFQoT`zK{x(aBNL{Qnyi ziIX+9iw->U*((?ygtK;{CzbMW00%7755y3s5p)AmL*UEJ=r{pYogX2?145Wb#sqF> zXkAq9HQ%ffU6RRo9ZYZcP~Nwj(@!uZll?zpixKIxokR?g2=c`~ucsQ7j;1DMu^2}% zrPA>CQpJRd+Vr5y$2S4#I!C13|@5#47?zQ&^!&PIl z%}Z{hOD448x6pe}oDbVB&z)I5*iz6do1V@YjGfrG}PA`?No8rmIq5=9=VY(+)G zN0gRanvxIbWy&E7RG6p>#R#zjF@!P4&iRf$^Q+HHdx`kqr+5H3wPW* zWoz3-gL!w^iUdQ%aR?Fph70$~`t_i-YbC08MS$}_cqp!Ezxrb@Rh15WwElr~?}xWN zKnOv1Mc6e$2Pt4p0E>eU#rdEgHQ75n+YcP~C?R?4HIT|mrJ(J5^1%6vc7||qmd5)f zSy{*Zj+pTcx*fzLHBG4gFX|9cOeHB&55al0kC))bp5rs>b@U?q7;pZ-r)p5a3ocLA z6?!6y1jSVh$?M7wAyDZ9q?gVj*d?H0U>#K{ECXJ|oiABBCFMd9&A&H#jVD;(&`;0Kx`qc1{q&aOa?-cei%y`u*Rc^R@3 zMDGn(AYr|b!01$!-T$gwLyz_C%Jb7R%=~p2*p=z@9;4qKgaR?9F+=GVI zpc?Wj{uZMUQ@n+ACndl>CR2sDgKd{!j+rhV?rFga=G8k>J*m^ugR2@nr1Xwc2rx%T zVd1(Uqa!8F@{$;%!DDLR1A515h}3R^fXp)ADN((nU6Ry0T7{&$W_P1N%9d*eKM-ldLm-H#>Iw zMv7@4IN_R5z>bOa1e8JU=7@eWeYpi$a*2+6{#xPJI`$2IL*>p83f@sv-DPoA6){DQ z!f_Bb(S+|njx=zcBz8x<$jYK-B8PJ*F&l6f0nyr5brJ~6 z1x?wOlWqQdh*O3tlyUTO1SONIPr^clw(Uq|&u766t&ucT=6jmO!jJnMc_36VNve3n zuI>!|MGvSL#>TiuNDb$GIHwzL4aeOo3$jMm2&yCRarElabULmp$<3%c3K_p(s_Q^U zCsp{Qzo(~}>U%Y=6X|3R+aEapJ57W-mt(aXap^!dfjB%Nc#K$U#B%ay8X}#XA64*p z3r5uuh0BtaDdqa75-bNwgVf*V!9vKj*68}d=m%rhIc6OTdhqrJ&BsWX)4%IUDn0Cp`2|aRl1+?)x!#PZIV$%XLp-ZvRBBXtj zkxV6C_{hdEhVDH&JV+z8O$w91^OTO1oux zpkPF%GS)m87Sq0ojqPpoBBUiQ4r%0P4wf+zp9BXf`qCrS8Hu49j%dSjZ5I(sUl-Qw z&&2(1Tm3HGozDq`ISsA<&k1@c_J zx`m7eTvyE#)4F*_2pQdArFS8QE+6m}V(TdeISd9(5r%b;`+ z8{^BX#3!Sa-mn*9RdC=o)I4aUOpywbFf*8gI(od{UVaCgUnqy$AA4$$Hbyee+^`wB z==Mo!AmO8cs6ZTWRUq^oe%#{dL)?#$)P$RgZ?FT8L^z&JEHPOsAjI(HFJ+BLu(aYl zpzK@1Dm8I1?Q%j18$pB=REcXb(+5sEjsIFF0FT_?AfL^wNIwM8k@Mp&`?5#D+m|Ko zx20)oAT=ru2=2hHPB|G9q7H*k#>W6hyJUldSGh*?XcUZ$?hwmXSx&=P7PAfiel@}M zIBf;Ay^r6Z#v=WY2ZlyWG^+mtWLY9+D+xO3Xp+I~qdbr#ucVowxJA$ge)%hZ^e5~M z>D}PLSl{r(R>0wA;BjtEJh~jY`|X8X(ASd2zIP9ydYG$2v@~+ZgE;0_0b8RH65D!} zj!8Z7by@Tdb3i$3=5a#-u8v2`)9+Y{)A*LEP23iOdq=}gC@p@Ti}_z?2n^I&M(xo{ zRVq^J%=2@RZWCwwB~AUfl%c-V@?-z31S>xkQnp&D7?}azvcg(iDcr4~I|)|~0SSf@ z6QpsE{w09@F0qK{pnXFGA=pYS-O^YT!zfcI+z3}e4(6mlz(c)_7=w_$8{ilneOAWY zNRsuEz!9=`5`l)Nci39$-$V{P!jv$ERcmq-b*F>X6kl+agjAwbm_gfYJ!F)I=Oa<5LhC3jc zfgdvlqC=q#%Ve}_ib`*W1x{y+|dQ!<)f`H|oIGqgt1 zv_k!pJH3+Ycquq&v-A)x1U&~UKSLZUguG4$L(6$ko|7yuHI|uXf|7kB3ePwaM8u`L z2617y=;z{lEzNV4Ya;&d|HfO2gK+5s=Q!d%6YR-mpmXHM3fq7<+?1^bmgX62tQU0c zYsl~5H#uvj@u>A6pR`+}jXjQ&p_iT{L;@Q*VwhlfER@Mj-eb*T4Dy8cXibGNNVmLr zOXsiV=_LRNtL zpfP*0!blZ5^zhI!p~&zTF^ci; zz|l?U)V-UE;?^OJ=Bp=G7oXVS#Dm(|Tte?kMENbeU$%Q$mqJ^mh8{J>v-A1~+`pLX zGh5KW$vqGT_cOS<@#nDASxykb$gsK4l;LC(>Ut_lHzo9aACAVo9CZk>p^9o@7ju}A zK}`F>WLHAjN)(=XghoYx)Q{pDbg;_jIw#hW#3J~bAV3UT*;OqHhB9dz@FdX~{BVMw zlT0@#@~4}@9`7M0{saFtGr?Tx8XWjM%^A&DG%Ha*#AYG1Ih@joN`-e2J9xG)t?{j}`#h#=?EP=y((Fi!CnkBqTc6R>d0^VU4_jeky(>dMNvW&AD=NF`&?_ znl*E`F1*C5(qyQi1|Bc!(pclc!zc7U zyqnQA+{W-Tm5bheVzJULl)~;i&d*+yNnfNM`91sOFsHY4!s+=aGXasDo)0)EQ51`} zfS6_ZNRETyLiXi1(+S^PF>tNe(`z6yhVC5YuBV7w5H}*YXhE{jzQ^Cb=A`#ECVeFoM_iL} z@|ai*GPQWR?ZBVTHadT;tN^S$|TbGpb29&T7-r1)JHf@`Jzu=7{d3u{E0~VO`qwQ z={VgYat@Gf3L_h`zLDz;QB-V|2r8r4-=aq(zFRV`QB=)+P$iJX6gH@2AJm8qI`x>9 zygngKG3y37fw-R$QKL!NA)kiV8>{$n3aamI2^ldv79(?>vN+5j@3@u61G>!BeuHqX z;Ub72Y<&)=Fi)hVBjt5K%^rMIl6l^2%a}YF%e|z-@pV|+2vAlCQBXfo5$tml<`s0N zzKhH!in8Dh2^66rq3moUM{2qc@U7IEjoublZKWjn3dc}P4+hEguZl+a=N?-gS%u*S z;Tit`J(IUl3`(s>MPSMhY9)(!B{mVZ2XgB?NGs>`w0~!a>MJ$mx6#i?N2F47K@n#g zySewMC`9TQx4u%ERJmoWIMGSap*L>Z57eZhy#eG&MIguJb^|u^*QF-ZsY~nR>j-IE zp*xSh30jBLi*~q?)*(XA4ocGH2MLaKOIzFU*p>5*b9=s+7TQV3Xhgah0CLEGMfo9R zy%PPEir~m8t4)V0ADVDV@r*EN`9kuYf{80sQhOwWEhQ=iTDP!&+JH`0)S+VY2q|8S zuy_FAuM${8u2qccASibtpv*i%r*)XR5cc=eG;pXi()-N_=V>LJD{)I?cg$;pJHNSM zcqm~!J3vwA*+$RN;>9G3^F*8>ZP|;_Lgtj<`6q$a^L`M_;6)@aOV(xjhKHlI=juRjy3WN--4P5)p}f@FD$@48n6sW7!jGfP_L*iRZqADIXMJ zYD%DPM{rUtO>BgBW!)1R^Lx36Sud_ir4qXhmMMxdnf=xA_Ef;a29OUWFdp+r__xgR z6P77EBu4L$urqSKWo|!L0|ePP!yqzvGR53GPt9IV$C?WyPfXI{9WD3#PP*bWlE8(K4pBPMV9?NrqE3RE zj~%NthwnWI?t{k~lCVw>tX*7()Wr3P!8qn;=tDCVnY5(_pG%BdA5g_k5c9LIIK^n& zCLSVd52w9LYT|ZGyhu07D3DvI9%06(?rv}p_kiO_wRJYD)ZMuvmDBB3*|6S+4hQjU@{Qyd^DU%f$~o8YzR07bsL^3mtJN_TKv#~5 z>>EN@=RHMzsSa8QL8BHL>{dhzLSjc%jov%x6{Qu+2>K6o;C8r-itmv~T;8wq!5G!m zU=?p_bh5wpVxRc=yWXh41Izid@~;jlFsaWn8Ppc7ifM`#D$4C1%iXk2UU)0TEpGd@75Hqn^qISDNa$Qx;TlSiKoq89WsLNFnR2q#5)uL>w0W((sC03WniyjaPl z)i=Qa%V)orH|?jjj08nBs8-NR9Dy5kDw|r#WnJPopSE z8n*+&p=D8u(?o>NA-Fnm&6aTiN90S~aYQIuK${YtRYKE1hznpS61Y=h-Cq1?$SEIJ zgtU>&-)f53q^=MKrQ#`V?MNm13x?1UxlXbqw}7sU*u{nN|DHY)aRf|!Ap0HNWY9+i z96qiB>YkP3h%2N!uIq`WqUNS;>?-SXAjyoBvNYqM=EzREOIrO+B|y(KGCVO)fhyVZ zdtwA)z7KRnk*hc#f@MQ$ZN(3J;&|eUxtvHRx22*!T9x*~Aj1^8@aUsnQMyx}ruRU! z|K7a^GbToPTND{?&!M8jxQ#^Q0Y7l?6>hRl$k4C^v-2xP<}yIkG<%za1O6=%6``ZffX_SbF z@ul%i&T)Qq!lTT#^nQY@h2>R_xB}iVKboM@!N;pYB@q2zbwc%)%9}41bha|#GW?z$ zS3K-$WRQ+b?yUqgls~kpho#3~*Q?be8PV<5jur{_-s?+*!gjTC?tg^j}Ae=_E zn%HW4TZ&q(l7NB47GzYb)q3@^PR&%SR&o)lAv9L2RYS!D)Oo8{j6*%-Xu-*Vnz?*m zy`shd_&MWb=lld>Zsz{V+In&-%`{TmSvKQ|f3;T@A(9B@MLn-$KeIjWZy8JcnJv{J+YDw#%`KJBdx!ZC ziVjXn@9HrSl1vV~mLU}(ZSVYqC}ySLqme!VwR_^0>8PV zXa4EUav8t=z+sGUTMi zMvZhJOvEG^d8c_uylm=ru01u)hO!W|{aO6-1Gu+8+Cs~rxvBIYI|TfHK0IPY2B#(@zWdohT2JYi*_H!yzhqzXH)uuiPK_$|S0ZFEhmm zow#*zj?2Yf(?)ZQ!Q(O!Lq?MFqL-+?pZpBQbE04&G%VCi-qar19oOWRBdmPx?ZgaK zH7SyFs*c1@0Vy7L%D0(7WSw(Q8T6Hj*!5f>Dgy;Hi(?B(ok0?5YF`&}wV?mlQeESs z!@{1BsK3_ya(Htn&ghd<>YohkIVc#@LLpW`L9w_97@;-^P`!`V|g5R#qEMHUO? zBE0JW-Pq_Z!UgxwF|6aF`oLy&qlg#!GorJbkibeL6*e5%pI7tU1+SBhm+1H|%nw~` zJ^z-xl!(P&+~t!xjC}c&#p}*85s5cIy3&_}{&nGhg(f$QW^5g-mNY@{I7j*LM!MU* zo(@k^N~dAV?BE4ppVVD1*2t`I3^40emSyy)jJbUY)0Ke?7?Bu`7rBV0aSu``F##i5 ze@(BnpMtu355=;EiVZ)^lT>R`Ux4_PvK*tuaz;s^7a=SgLk?JSe}TgqgMS?bFtT*R z1adszWxY@+J4pvFo_%XGsa(kj$Y_J&S5G0PmBjVMShFZ!a0{m_MVQVZx;qEJYikyQ zFB43V^0mU#sgfu6CXKQN)hpTZ(HcW=Uct82v}r!^lrcDolNP`dvF4wF#qKdxVAo;df@J zpOB+lWjVh)pULaLkwVXjI0oMAcv-N>-orZOTwtmHc zML@MVq~1LmVZFp9cdr?*qs!_p$rO%JbSs1nrlxYC+_5~Sr2f(bd+0e0R&Ur&8X;xL zYcvI_biy8KNnU-+(hAj5{l;d|<(Wc^;>U|j8EeWL^b?C0GfCGhBGyXF`q#fA!5r^^ zP`d>5INsQI+DGivXw;6yVor}kMZH&6LvKrOX_hi%;>A-GPm~d@d~Y)8nytLSO(J=D zKDbVW)xLQc3C~QT3|GspOc<$2Kb7N$M=1Ts%+SbK2PumMA$DD$bi^}dV;wmEmTq`L zrb*t4;aE}vQ!m+)E;N-nX!?peS(fAs^_xXek8^U*<>8FuL}nro+4)A-WkNom$zjuw zI}^5S@+{h#e%boX_V?t$n0t!jl>+FRM>G`59%zzo+9pY(4!fJ$)j)_BQU8zH3cpUo8=BNUuXjT7+_dS;?7uJk(}XHKl`-d zQTpFevGU*%y|_ud8Yzc0#IMU_X_&x>{2t+ua?Tj#4qn>O1g4SWCy`VSI%lM5;Kpjs z7_FR+{AORorp_8!G*n)k6l;h_rLl(c@+pPWvj01ug49wLn{8!J8qfnT%=7Z9A*@L@ zAgp@UDB_}4oVVr-L$1WrIXF4qq8}bhm4v~sJuqOK=N}kOJ3&5>Rgro%c5|#}GhK_uuI5kF z;e@GTy-}lO%sH8JC<(4=h#rX)j+M)6^NERJ)>8^lJGK6v*j>7^uE3?WZNb@;1Rk@r zz{Yc9;^GF6VY8BRXZ7?w?B-!Itxz?Mh3FW2qa1tMGoML7$g?=-VroG{9FT(QB8?Za z+{498bls}{t&N(=d+xrALDp@g^fKlB8_#asd@!`@L_;DCL-Z3juHX3bR{hbsschSc zStoDxei>hre67&*iOive-WvlOYZcI{7?>sV-9S{axws*{+$!-N+>|4iW6T6O2 zr?)NK9C$`6#Pk>GBDI5?9jozyW82s%&DYQw-Pb`~9AFW{s5he_Wwq&UzvF5~Ze>6(j?s`#4A&|i#YDiCyC z{qFGoQ&TTt^Py`H+CXk(RH8MqGd2;DI-!g;FKW2RHbH5?7B=XQd0?7M6r5?;shXzH;7@p+haz;*D?#l-cb zrk*PinNxfXLIyQNqweTge9D8@cD{=GqDik^DvO=9#_GjX z(MqJe`?;)#GLj@6A*>kDad~XGX`*zx6FdWW-A6`xp<21e7K4sR&0FvOMrckmrz2z zQj`a)Wj~K)Ql?m$3W+bj#lUgkfp>aJQV;NDa)d_MSv+H-qeP}a(eU3!+t}{52V2RC z-Hxrs&v_I))ZE-~o)dK(Rd&AejjN&^OtonfL}EVKUQ!8W5(A#2%Vnk!$>!yD}EEP7znZ8e4UEr<(t~Z{x)oLQACzu!BoY zdh!5$s>`0IZW0-+V)ijl;?tX7WvLLX-o4dW<(I+@R6lHm6pws5V`GsQcc?1uII^g! z%5h9E)l5wEDk+#XU1OpH*lHJnk{>oGd4vZ|zPmlq#T21nAd=BAqqXdG9k#f;sK}9+ONSkHyi(X~69;)B!_NF1S{r{fE2B+_>@ic50yk19oX1Hn7mNE_hf?xe*_vamRjZpi6)V;f96eo;4_#~W_c>YvvQXo$I zLpz6lf%R(o-}uAqtuJl+nZ0SSbTlgcel`@9JR8~3!f?t99cknA2*t-JxfFjt1p-%1 z7M{R(3s&A(QT7YEHEfCLfVOZDTEz1Us6Y`lq_Rw2C_}GvH`iP*-8Kyp>$mnvN{;bu zx<|lh{Gc!}=`rINN;0*5#-bjxPIR*uC>eS79A+b~O%gvKXP=V~N>GClCT1B;koI)5 zoIwOhW=0dD0E)%v#E*E<5ov|7lA(_0&IK@J5@#cS7vu9fa>d|Y7L{<^x_KQlnI?v6 z8??EMbkHtZw0jF(so+-=)nJ?y*-LIe!>ICs2oIWGL2iD3-+Pd$`na^s~U z`51~bKW&b0*|KI*vqdK2j*+?BotoC@LqxI0_rHnUQACWH^@Al67=D6=@~F5Nqf@yVWs4t_5;rAI41OeJ#L{77Sd;x!K{rWeT<0J){6cpM|}qluz{ zCD-}<`7tLqAE2t@=XdHZY1o?n(p`dNk|FOg4xtVzY9(upa79Ax;AYdJO!Z_+^fDAj zB+7WiE;%Ykl{h_0lIF7%09%VyebUh4bkejbed}`am#uSo9Jc#X|`p&Fm?PPwi;gB%)`-!lTr3LT8CgB`K6( z2~S@&LES*70w!kDL&~EDx()2ml6N1Y?pr)ZP!%SYC{xy2Ms*_hXAt3}uAE(U{`!@i z2I0bRlx-P@P!ut5xad#rh$UNPkFw0$C zS_~KhFlz#Z<0Xrzgybu59CAjS4ryNQd@u*b@j@M|7%D0wbPL3jMn{J69TrmD*BF?x zJWHkp8>_%Z@fxgfq_8aJ@RSanBx2j6vc!W_b){jVvcr?eZFvpq;xOQ-)=dwP0tMsi z1(d=(xAQm|Fo=>o=9M)5ESB3}(C-Z!nAv1hn?UeGI!{z}w;?3=s;1yMM>}Xlyc*j| z5iPCkdjV@PX&PFj@B7rL-bQBfPX1NKguf?f4Pz(wV+9RS1np?Q(CApThl zTk1sjtVu7wn8(+Ae+fIYB(3uH=~kSZ->BV(hS(Gtp>p+dgza+)6F@lGUsapW8o>kCvLxC2l;TGdhEnA{tCWTDySA0uIT7p)_fx{>R!uaHY~L+l zKUc2H*NRp5l4c7^_Rv2T2JSKB45{W-52Ad<21YakJ(fhQfnsA)oPtiYJglHR#QUel zHUhh?g2TZc+l=sL6N@9KVS4h1CBR72=TbYg3owX8^E99@FQnxgT%8b|C2ArI!vvUo zc*>fo#a~T9-bMz!B3wJN7@Vtd2<0KO&Oz1i0PZI2`Uz4Sgo<_t2=x`~H*@8Gi0|v+ zTvecuS*RhB0!$*v6I2g@J(&`4TNi_&8UQm|D;%5VZ09_?T#$O^OrCUZiE2;~m+_Ww z57&)T5qAW$=Jnz6ZF=>ngs@xsq2>JkHj+~pCzCW`7V z3;7RL7GTmXQ07!TG+4KuTC#?3aHI+Kn26Y-LkiQ9%^+GYuJ_hSmd#8@I|&flx(Y07 z(0QN=q&U-H#2yjrd=ljTiU($B6U5X-y*&*_w_~R9?XvR)UmIfaicT6FORUeDYD~_e zNa4ty+2m;U$;4ig6N8Q6Dh;G=4!zpPY;o|Y+7N{L9Hh{)#w(-r52XNC92>q&?I)Q3 zrUubN??Pgi5yTnC%!Gh=V3RgMOx@Kvz##LP`_w@2Q8L)O@)Vi)fBBC<#Q5c1I z@|kc>gLL??Liv1pM94?yXL_Y&!5OlSpXgnaAUd2a`_$itf7gC zzO}F9Bh;rqENfs$Hj~`V#4bhX;o<2sxgqp4oY%zlNE(1lT@;QNIXe$@@Vgh?@z10A z_-wv3@^v%_L(;ihQgl{@vQM^)GP2AI)%6a%*luoEYrO@2`OG!*MzNwBw11AmEf{3_ zvBwE72so)2Gv_r^Jg`6E3^2wu!%afYJ1u;VO5NrWd{n9u>U!793af*5N0(VSsU~f{ z@HX#o8#%-p81_`W?7oX1g0&r@!RDS40hrgpAo2qiVb>$uN7Dn3W1I?tr@1|hRgh+i zwZxkbtrVk<#gY{5yu=XXU(3Tr;wlQMe#Xl`>}**C`CJD1NPw4YE5p1L4@vrrCd-4m zf|r)wb_Ys_`d9);jPt#vR`00nIp;11hNslY=yAQHb`4qu-bd3rN~8EW$S=oBns{QO zE!}qnD@VIdkag)d0W2)v3@PuKNpFDmiE=NcDjYjtFG#$#PGYLu03@ zyVvNrh2SU|s+E>E`u0UszD02#!B;itJ>UZ*=hKYl4o^RGrX0KJp$n>;+`S82N{hM@ z*GnD@*`}i_ulaTwm1fv{+|D)rtzUiz%SM_~PVOZsav6lD;oMoi00e4&En~Zt%+`jY z{p4=M*=*H8nM#W%$J;lrHc(-xOVa}_dNh8s z!&AAaS$RFlw@d7TZOvfvakk6I=jXo_*U8v0Uj{~Ngphpt*IcT{XZedtYQKYKd#}GB z6&=Eu_h8A_dPzc|WvwqyxgVb+BAmETq3Xe@UI`m^8OBw%$FrxKYf#1nTQoV)0xqSA z=aE^S=)xOgXT@`_9Hhp@{Fau_M~;Hg2Od_2@hkrLxmy}FL(e+CahCm~yUklsDJUn` z-XNtK;<`uh9<0vs*q4;!d!s=Oo-Ew&NS*qyAnHAmPDWnwup^wy-%WGp1Jp&J?8?up){XR|d$@ZqqXwb6gH|)vS>Bz=7kPL##Um=p z7+XgfgDC1fSZY^8GO?n~bv%U0TB16we@bI=aAS(_B3LD8}V8u(MU3r159=ypIYh-nNw^17RYgJRcV)U`#}J3y?va zt#Sk*?l@=Hw|Yq*Lrr?`8e=Fi%4G&9j5Zt723It+Y4lMY7{v_&-taKFq2j0}W8z49 znQerEW<`NPp<29jPPg7i1PB#_1)VWN-X30{NXVc~u=&W@ZTByrvku)jD_X#Sa0gjnY_={InTc1@35$FU^r1=WJduV%@Bf*flywTymo_nu$I z^$iiv92%(}YtXQ8I0vyQdPN$(pF=X;V&KFJs-ncG!^#F2?Fae#RW&P zhau2LYlIx@x=?1(6qi9|BYjJ7Y#1K4Uz)G=%5-%Sqfp=Q@PLCiN-F7`bXM#^10~vE zUk6ReXtKvssC$_05+jeO@mOd<$!$$s20Fl{UeeI-&BTF3|mj4}pdAtL}Bz{MR6blXZ#dc#Oq7y}BKW|(Bh6WfO6tIN@% zaP$FA0rJRkN60MI=2M3rGqb~dBb3o5wi%YJ7Pb2IKEOSLSsVjD1oQTXc#q;PaYs&W z*1j@|mBLj~3T5hxR&B`+_cFYNhP_c^UZm1E&}ckHm|Q}qk=fIFFV0tt|lQ=064=m87AH({TjT#oPZh@bJX#*I?#0Os6ko}Pi z{B(J)Vb(Reh$*Eo{t`#*+Y74{B5E_CjJ*oO2&TW|VLbtY2HF7g3_>kZc$lDYtX$6| zNNan*DWKL8I-^W5IvR6XP&Dx~Z&%~wgotAbh9|9Y@|HDdS$U1oaHK`Q-bWxz#Zjn- z9J|wnh!5PN@}ET?|876!dmEfJ>~?&W(wq4KL7iX^qgjE-mbziI6wWkaCxwnoP=3ZY zSa*~jpbSkmDeOSShf(VRuLQ}_Ne%my%-+jlL92&%djO9HMfmv6+*;dq+yu)ix}Zd3 zAndlSo`VCGkLlR-KpW64w8Ow7W6ki1v!{gn<*cZ1FLl9GQf{Rf`2@pldbrBzwdA6$Pnv_F!(2nu51$}$!mP!X#B*M8 zseuujO6hLYq|d?j86)vJjL$8HLRscSEN$XFwa5lLdg9BYkqR?jRci$gTW zCNC7aWB0my_>qSdwR`B)RmvX(69*?^Vv&EA8R}>zisJmVi-i6Lo)=G)bzo>d&N*b! zxL+UC$JnWYu|GrXg_mHQFqapfp6A5k3vcgS+|@X`2(Xa=0<{O_`FlBSh&ib-M$GUf z56%ENj4-O}@_r9>8=5IKn(+-~A=$=RY(PheD1;)=3is6@3sda`f-({pFy`@Ymy0KB zkV!G7@Q+p|M;}bhvpxbwp)A30JS${Ud!Of#JW zK`-Qs=S8apT!yyB^6+u^Av9igN_9XN3Aa$vE$yeN6p@&bCcwrPS~-fpoo4s`K;73a z@>mW?FDI$fpy8<}g;n4vyDNZ2A~hlMC+(BvsBK=17{`FS52)be_E0KKEW=VL#wC6g z%x~B*vR@zM=}qjFV3m%n8NakS&jb?#j1sKwDT~bGu}8WP;~jd0PT*(&AXdCLW)V9B zg4q@AA&GMKf88RB=~b{ZNwE?m^_Wx@NMZLTEXs~hzGG~7V%Le|=fF`g>tD3c0SBX!_-v|&!mQ8cnYK8G z9^lgte$qu#(kvT5p!)_GXQ=BM%Su@G z5lxGkURw>?F%f2=q+$9dv5#%2$V6~T^{##tw27JMlo7g6{ewr#IJ#IF`!f65hFr$Ewb@}L}NgDxV^xvXO^Rc zs-e@?L^vUU1C-Pe_4ELN!zFunGui?Q7&5j0Yahchnj!8llZ~WNDX~dJR17W#n`&I~ z0h6L}h;yL%AitB+wm4jg6eC@Wb<0|f>v9`}1$2#3GiJ>YtWKL)o-L4>wS0+whsqWD zY-|*woSwAr=UZR%@Yduw6PXQ3Mb1Yrq*y3R4Gq1WMOz%e zmWFY6cWd0;gS)%CG_C=HOVhZ!6Wl#G!QI^*f)gA<(3`o>%wL#QZK`%>QB~(V?+bT^ zQj_a~LZwzO zpwLBJ&qF${rIki>BIw#~;kn3nC)C0o4$uRfv=9iS60PYgxbukrp%Suca9ZT9H2_|U zH$F;ug2y*B`>@LF>201NKLa2dkGGh7i($V}xT4GIn!zt+u&P@~L3)KZCjxy}k9bry zYW5)py?!FeGsswxuVke`OyxaiB<@X~um89jFULws!95)UhuyhH;FqSERK4!k%a2*I z8zLB{pwG5(ma?<;nZe-e-0aBX-Tn3+MgBmO0mORBxkJnkM72-()}Lh>8|efLevJ)w zd;lsk5TVqYmm>4cFiztzJg;5ttHSr~+S64MZ%-g-u{=X&erL#(TfIUp6AgN@)CIX zz5DE^`Jvt2DWAGNNDw3xT=3@+)L6y@ZQT6e?aA6%Q6%%kaR^Y7X5w14Qt{faU_$+^ z&)bYPYu9W#uA;l<+iv(Y*3a&Zk67uydW^S;e_U11lxE7pg2Sl?EF*(K1CX5J6EB)j z(pq_wivYy&Ot1g`-~@j5;|F$D*`k-q{~MJ!Y~~RVDK12mraCh|9NIRUH{b{~$H}Kl zUn1{W{}aoupw6Sb>q>j5?F*YhPXF=$PY)E(X)8P zs`TdnL;$vcgftaA!Wz@->o^`@i~!3fHLd9gA9b@h(r4|-HHksHkENL=t($R=zGHf7 z5e#PmLqEOCWztp>6gekF9qR(5eo6w%5{`J5C_r25HlG|L1}N#YEMGFivA;c=#s zW;})B^&WP8Uix2U<;2a?^f)f`7>;HF5>`fPA|F=rhhJ;Gg|B>~!%4Xu*M;13Ec{rE zn-hHAL+@teG5Gk4TLO`Zz1YEkEZ*0-10}3#lRyNKce#$LYb)UV-8!qQ4ggP?ONXC# zP<3rPSHim|+cyEB5n37nBC_=2H7%+ISL8rw`^^2G+*8Gx>!ZDYUp-UgJ!) z&Y@zvk^NNYDzW2qqQCe*DO$Pt69*pmlMs%c0W$%il-qp&1#Hr+SiKhWAh)TU+MsQZ z>Wmh^_AB+#q~_!W&iD6)9B-p9H_YmiU+k*X_csY<=T!FHCBsn5tDeXkzNHNjl}V=Z z5uOJt^;SRuOW1TJxUJUaegdndRvpFr_AdL$-|O6WQP#pL9JlR^vn%@;r1BY-=2a#U z8H7JXnGr7*xpQBwodnpgGl|mQM@HoqLJ!11y~rtaIujp5H2yB~#gN-KYJ#*61O9fVi9O@Tn zI8Hm(aDNG@3LoGZNYykH6n(G$Om@i~Lh-Lu>V!?nW8>~OM@{l36cKeIVoq-N_BUHh zj$YL%w*<{gBX6g7e2hgw>epl9eM zQs}Z62#wD`VJU&`?!c~fRDIs;>*IzJYn()=wy-azC0E(!tn_du(z8KRiu1Vb0&D=H zV41qPR3QT+k7mi;Ai|+gN8`b|%a2%Wq^a0@f!5l=I9@}_zRUrjv@wc0;nH&~;%rwI z;;=PW>*mCGb3~QL5Q5G_lkyjJ#UWb!9!0Wr{D>u1b6J}|YT~$8?o=mQ8_SJo*r+UO zYMgfiIck9$f0Ghl%tB9ygM~tD&7GG7oT6;*ahm+_;)%;@q{v(B=8K4}bc?zw;*v#F zdGpX8eW_U7x@Vq}zKp7nIW@-{tXwTUWzzM73m5CNh$5iUB$s{R^9}IHM@U?;sFk@+ zF^lXV=lSis9c5Ugu+Gd*2u3%W(z3i|oD5Ry;=NhKoKhb;{^qu4*gvogJ^VTkYreXqp%yzGKKw?r8jIdiRgyoF_|xAX!tq0gnr%cF~RkBV=&;SchXsFvE9=Xn#=kHX#I{chCZtON(j1-JT$Nfx}D-QdnIw24xQsLsz`CP zrc=S%0;3`(cgg1m>_bB7E;tBknJh9W+X6W#&&vL&Nt}Si9#EI~qTh1+S@b|YCoJjc zKHD&XGTlUiXJ)G5(uCOy2&)ZYsoY|n#_)eHrEW{l8g!Xrvt1pva5%mnn*)qk-DtEE0Mw-#ZUKoK;;DR{=$Zp#+^eBJH_SqV=B6fgDiR@`u zA2S=*jyKVMAim*Qm}8?!b8RMH{J4-5q_pAn`x?~}J)_rk;zRq2MU?{Qqg( zC0NTE3dM=uxwBUkpn<;j;C&5}h9iLlqokV!DiSTbKnSVwo&g>WPOPVGN&nQbLY`;@ z;MQA=SzI1NL(5)|)wd(9nYW?jwEbHGTLo{pBZzMNZN5^M zF1s7x_vZs1P0v$bp6I0n&P#Tim$GG4=0;p*A0Msk-#^DG?1e)_OZh6sFHBr~zp$EJ zlpN&WO-_jR)NjQ$|NKeve%=g30k*#dwF#Qq$~_?02%3*v7A= zT=t#TUekW<`*^A%ggzb<(T^JMd@X(@;przdpAl=PNMS%pk#L>56_?jwHyR6yP5FL{ z!L3~%N>atIkb1!ws{pp~&wdBzGT`(E0N0N365&m?>C3p4SQf-tew4U9mj$%YtSGR% z-L7RfbT!~jO6zI_L-%mz)rqwG0J0V7;xSLdEv>_9TDsOZ-28VNW2ykgAGAw(+nJbW z((Ityc2zw&CAVFHr0nU$(+r3Lnv-Y2%4gOe;u^=PQsMI)s<=zpi0}9NCyGC2xqpw- zK)$27#}ebb?EifqBa99n8%l&W*qXm9g1y5d@Gz}e@%SZfcNv)5_Lt0XJ>Mj@B2j7P z)k?%h@FMhi=}zT44-a{S`62W6nOIM8$Q`M}hy1@8WC4xGCzB?geqr5>QxB>8(k$9? zr0EH!s@=khQJopO>HZ+Gg$wRP4bctCT2ji;o{1ik=4n+Q57d?Gy@gIIrfbdRAlvvd z1*~e>xe=IckDX|pi(0$yoU-ocD}(8N=rX@Q$@f0LuLf;;CVZYGZv)2~77P9;PGNAcH_j%JYLLO=OCR>Tam(l7r zhr`D3BXCQK{pcSbK-)NAM2zJKYP*g>C-&WA5+x zQF6LAfN}S`xq!ZNH09REuh3_g@W|5Pg^8%(%13Clw;TB zgZcvPNWFvjtN{tB&dK?ge8+mOxZqY4jlufyMU4=^L{s4WPPS{Q8Tf=6#P&^mk#=gVqT}I`Y)E?@g@4F#yllF2P}MEb~&IA)VqtBV;F#?5vvi zOURg;*;|Rmr$9{ITV;BX*{op&x&zIen4jqP+?!nku|wUoLY7V};B3m=9pH)Y3jg4? zT^cG&R-kd_Whx$)@&T^xR6*ctZBfwN-C_6TCwM?jt%1+4>ARu9R4i=LJvf|A&x7Vf z*5JTrsxn|&8M|OT1!}Lh*b_JkM)2;Ty8=#_k?mh60L;jIm97%Fld%2@Y@$;J;I^TF z!z)=9?gX;xtcC#3hCQz1NhaI;z2q`?Q!0d1-^#r`j^wC&2YoHJ;mvn4dYa71QR1(4 zLclUzj~(KT!7XN2E`YyZR=oUoR=1j2{00%kcCxw2=qt}C*1lNHr_ISy<>#8sm!bz8 z?|31N1rcv!KO=sc3MNW|Bf9?af<77}Wrv5jL~$~)xCS?EA>Cm4G@=dqdp#&*$NrGT zcnDMZq6^)^h!MxIei1MST9H5xOw)2JKl~=-x>t}Yw`qMv7T@6bp%?kV026t8-FP}t zH!3q{jIJWe0elJWh(itO3)&|I@{KRQx~1e#PF+aXGoN>pPbn=^jvWaD=hIqcskXFd zvg)>h7F9k?=p;LmGtnZTM6RunX=vmmV1WNzxfb+ht)v z#F;^Kge@)HzVzAL%jsXAFSZU!eAKkZIDc8R1x<6h1G9fWNF67d#QKG^T&4GfIycA#Pg^VeIqln5ZhY>16{q@yg6#?4 z>+s=2=KGoQJk5r&N7tvJkZy=(_uqSCaGgX6&Y(u%)o zoA4cP6p<{u(m!zLZv~IN1E_!Bzsk zq;2$PVDmXvJsxBTGub_LDfT^sq;<sj6}C&SzR(DPH9DURyk^KW^D7;IcjLSS8)MwfC@S`*PklZZ^;Z!js-h6 zz&xo8?bM~6FvCkjxWuz)F&AgPFPwXRi&iPHiydSSP8Si@aGGf)P0Vhjye#_NPT#ir z*T?U>vf@o(H4Nm!qy>9U3gUbaXc3);WrXee@{$Ln6ltqJU`Ne;b|b6>6_j;{%a3V3 z^e?mo-O3>piBGoD;-hQ?#D{8%FEs{a)Y|dp{q#cjk}AA%&y6ciCH0snDberW`|fyY zZAz<|e&(Q=boN!6=fVY8sb(WDco%RmunBQ9o^O-Q8X>1KW-FAa=$9PML*hVnFvJr~ zBa6BWo?%6f>My7*!%uaswJmsN0`hCZSxp+Ck7@K6EJVw&?bfA?_zvN&aNQ_lhAp+! zTiY@CiA11peTe5P*A@rnBBa(WW-K#pyXmKKRm9lp%`PEhZ1e6w#~cKDv14+x2Nzy| zU&@t%)Va3X*6S>lRNLy%8t{gfm&yzM?Mt9WgZ;xumV5%4FX{bKirG={L0<-9IQcau zvGut@2Rk)`njXrz;kO0x3+OVQ4q5%+bmvy2E=4Po8vqpzOpK*FU(2{=Au1*} ziccT{V~?{Kh8;5}h@5IGPqkAUP@u@X5iIWe zW349=mFuOQN_X;5NW&TqSnfvLt|jatTZSAII(_GirX#afJ56R_L0@$Y<>m*eDeMY4 zGCpGcOz*GK){t47|99Df7$q70X$y*%Rkgf;6<%l&GjlhU{LutXM34KQ0uDr3lF=q->x^H`u1shdWTUs;GPb6w$*aS6j_>P**xU9}RCYwEiOmzbs`s5Tz%duo&({_$ z;n+9+E|>AWo4299Ht!f27_lkGa_rqReZZTxTrcWNotm`v+{0N)D=(>Fsz%l{p~{8( z=1y1`QsTb431zsCR>Iy76&tgqSx~`9W(241MIb+Uh>}#7D2x@rHrg73jrmRG?LkuqM zLp-?s#qY>kS2HsbQYfya)QOBY++^8R#oj)Xh<0z!xTo_${GCLYdK3HF@v0$YKL@^$ zm%xvMh)DW0*<*!IhMsZTso><&9q3^zhDDeY(M03w5E#c}!bhTv4x`8rIO;=UI=jgH zooNITudTU+eR0N9GZRB&NyLKUst zVJafMgn`FENA7icqZWUdG^*Og!pXyDM`etfFJL=0;3ue!0JNy_B2ueX+?^gu6b3x} z@(F5Og5xU^1@#m&<+9*4`8ETyWb~46nIE&g6c5CEjeRWgqXsc!pbqF2)UYNjb=Wax z`^Nm}gOMg#m}_%SD5AK=aZH#LArY>FIIulO1pjA@T^V-61BVKp_p*F`Tm%$5_ap9{ zW3mG?Kuh&at|wa~G;`cv;!89=To&!4M6jMds`b<+Zu6S;F5f{Wsjor-lPs(sh!ZSH zIag}i-F?`I$wH8Iw#Xvo2z*C>VI8GODz>3ePRqNw`4Q$kIBHEhRHet?hdrPdLe#*N zt>%RD6T=X%S5oJ8&xjIFEBl7SSsy_T8v}9J7|PhU89G^wg1T*%UXdc~_i+>H@v|h= z$`V0|@MywzTd}kZ=mS!Ll@WxOp8Dt0H$Y2L6+TU>4 zG3d>CL*QRI2y2JbWVQi=?%Ij<3^h+%5dikXHvpe56u2^=^Iq`}V^MLl@0iPw_x2}E z(|9PtLVy@meuW(P!Q`v+a0c&!YzJ6CIfSRb=A#s76&nSi^~Ibdh>RJAlu*5ph@$m_ z$3871S$Po8k$-TaP)(hq25U=qR=L{gj}{tIx!*cT0dIQ~RpMRQy^A5=t*%E&MLaI; zBGH{YC)}nidqC;bAs!x~9XiTh)X4#pq_c@cLAfVp(|d?Pzh z%B;S@Hdk7!;Cq6MYK-o?dS8NbP($A43hDRJ$Oyh88}mbyDjUJGhjJV_=_<(;{&YHC||f*(*m( z5T#^j@Mi=p+;@V7OqPYL(Qtn$X<>-7L{Ird@s}Z}Y8nssaGv@DY_~&g{qAHjZY>T_ zr^2z3)$}MMF2#RkgqULg=kY(#UC2)If zC%SVyO_=DzSe~>`^cOZy&WL4lUbK;<*Hs~&R1`DnGndqm&#n@4{054y_}?JOev9>1 znu4tWx(%S@c&|x}kx9$(ok34w|-Su9Ip$5l9Z$APeV}}UCx=LF#R}Zh;pSQBc-A1o)Ba?*;FnML1lk0OeX3$bSG(lEfeN@Wdk1!$R;* z5hTd>GEcs$M6YW>Ua?MF^dM4Ea9uWw)hVu5#}YQGV-M?*h#+9%W+rG)89Y}wC|Uc@ zy(N}J7s^N5Acjh z#e?lR5CV~}o2X?n#S4Q(luoN_l~f5@{2#PFYg;^o=Smd>dUo%~X)$`iY87ibV z#RUZdNk(q)Dz5aJ;xp+NRso6gh89l7=3Cd7ad~O#gnQdP(qGfGFTMYiG6Zh+^Sn_z zWrnCqfBKE}tt6{>lZXg(5i+?dE`N$&4!!}ucqSxgq^!LMVfC{|SvO{ylKSUl#h>G= zwPzMLC6;qOwTaMcZzEhC9cY^fMq-vUVB=-6h3_DQr-RBNk)JyfAU!TH{~>J=jn0eWRuz@Ut1=;8ZH1u zG&SUpBC4!NYW>?zh%Dc&LqZYn_xNSz({>YeR`P3|Ex+ADUEpzPc7xF{ z1g+eLnHJ8riWug80nv8EuR0h05^A?PlzbQR*S8R&%cUQ?h0t`vH@~eEdW&}CkrR6z zzkU>}P(B~|Xq)vy#CQn(6jWan7OVXR`&${$S1aA%$0hDRcMZE!7x(XPm${kcMB$r^ za7ch%N@T4n)!P>>6vB#f)j1I$b1<|}Lem-B9u~NSf{(9Ihr@Ho;^>+lT5p@8 z4I{)U%;@M3^RI1%75X4!a!s4C#4b;^-h}6{Q0?e#&C7b1PqivCof8N=oR#EiEE@t- zFm8G5D@lkdJ1f*NiL_tSTo)50X#~kpJZ+Z&!z}L{jhu$W^7 zeG7=qQ*d0}?6xpV5V-?Qo=Y87vTGRhRdRm1JVE~_kZ$8#2k6zrEl5$#3%hJF$!lL>yb$*KrE}4R} zs&SyYv052p!-|r!f;<|1+FNz-jUX1;zcmf=PD--zj`264_-fN1wiJ)t(gA+ouu95F z1(r?tQWlwCN~sBRx;U+g%~{|&1;^)t^a(2s(UM`y3nK!+slX8H8IANB-?5hC<00tq zVP?Vj((_N7s8~baxE*3rl)W#6Z^|MoD`5L$T}WZCt-`BH)sKzZs9%Ax+Im-LNfC;U z^66yY2wpxd?RLjqzRSli`*Fo!&0pTW%hHa9@s&V~lM1FtJbO_>b|nhSGRPmz2xtbm z{u>SO?Pf-zTPP`*oW<@?F?7LsO9a|?E~8?`%z=h1JzawTb~ubQOBwg!XuNYiKj{B%(6GX36it#N;#)FOj*4x6n!w*H5DcKI&h<#d9)6<3&@ zeEKd%OO%<+u_4cAdD6C*>c~PQ3QE9r8#~EUFR@8g$Pe{{#9ku;9*Udf$ZohxKY+3jqx4lWNr!lSBwh0`dgsvhu{r= zS6ju~pG-;EBR^C3NGz)fK2Ujk8%*yY2~{v*M{O#2D)+n9jmnnw*0&^UvGe)z&eCZUg6XDK1roe%(bV@wqkZF8TPtRaHhRUebEbTv^w4reE27 zqH)_T*xHrb9^W-UDDg09@*{E5d8jTL>!4%G$7f&clM}c0zyqPeJOw=tI9V)?AIHC; zgyT8Kk4c_0&Dn~sxVm&*5m{GNmVPN10^oj0up|I;cuhlRTTW*6GBpQqun57SrZ^$l>ixeT|O%D|Jz=%xRPAj}2*quxtUR5{yc* zmMXBC9q?*bgY57+RZ-ZOF#8M9uczLxT+hMLmok@?)JozS&i78Mq^Cvz`82m3F#IXCwa7ieJx+eD=C3krw`DnP z!?a85TXc1Zv7!3(r7i)xwFARd4$SY3=o6g#CCJR?M~l6>>WVuN-mqe_l;i6DuDYV8 zOxC$mE}NcQh*fPZXw6Zm>8yIX0Uj(9XzGB<moRKU7y&MTjP_ z<{Ks^9slL;&f1FHp0U3mE@LK<7~&YlFRh&TZnT#d5rOa$2Ur-wFQgyb%m)nv5-5cu zAK0N2spH~7V!`Hn!8%XTg}eu4IXEnLzGIS08J~t>i_@% literal 0 HcmV?d00001 diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/compass.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/compass.webp new file mode 100644 index 0000000000000000000000000000000000000000..be12e23eb4d2d9864fdd2f34d3a80b85597b3f01 GIT binary patch literal 15774 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%0DaYsJ2D$W=wHgHLK2 zKxUMDPI0XF8`cR$G+XR>-%Gq1%$dJP!&Uu^9=q@bs=qmF%p@r~Rk-8k=~#9%9O9?& z$@a5jRwImGB^b2BcVyUTFwm))q>wg)sn5Q%OlgbbRehUj@&V~2B$OHKUdSb9qAj{8 z11!0r3H6u-*GQ}%<%OI_m^`?LVaE_;OwtMn^oy__I%JMk)-&b{Vs_%(T{5)MM7VL6 z?RKf<12mHUVl^u_q8#!v3xyHp~p4 z+0ygg{c6?xd9SPGoV@^?s7q4}ugfbbe?9wDCEaus3eTX!H|>

qaZM zRnyR%L9XNQ{*(Y2mZ-C5xx<4Yo*qvI$(ZJlVnLByVVevEk`I8UCEzntSn291{zKd@%FpsoFrNpKAsWz~u(o z-s*TxRZzjfV+XOc2vh+ecb$2-3zO(FD!LJ#7EepnqP!WP5U)ebibJE)}7a5D)($hGu1|O(6*_;qR_2 zW|tDFoiBP*s5CwxOUD;CR`5aUw3gWAe-f*ChOl!5(ln#A^e!bTo z04VzA48iPL`iYJ(QGuo)o1`w#5BT&oG=kw?8yKIEi$e9Lf_t$j!yrrEibXmme1pQn zVas3^F>e~tT8tc%i_>}eTe$W)m8&W{>tM+Ga{G9#A~;*7)p>xo{wlG3m-Pg}lAkb6 z!C|^^bjGmcRnzp{NiRu-TX1g&RX{r zf0vmO$lXUE)|l&bS22`}H|gX(M(5*!ozCk7+ztZ}0ssIiKqZQzc-+8HN8?ZLUk7ys zAPwpNONL$m{yFQTAg39- zS%*sZi?2Gzh%i{%qzZTe5aITotvm~;*P}Q8rw0-DMc@Dc2pT*@^?$05z=Yb)HeDd$ z#e$FQbWq0Nj~uxH)=SP2GYt|R0*1`>#QPk8%~1mX;{9M34~ cugJn?{nnjH9N%jI?2H_}5bQcSPyhe`01hxwJOBUy literal 0 HcmV?d00001 diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/icons.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/icons.webp new file mode 100644 index 0000000000000000000000000000000000000000..50687cef65c44bc5369c822d5e0e6af6946f6244 GIT binary patch literal 17610 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 literal 0 HcmV?d00001 diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/plank.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/plank.webp new file mode 100644 index 0000000000000000000000000000000000000000..7190cdef078445b45d629b49af03ffe62753d0fe GIT binary patch literal 2660 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 SyB}PPM~J==xVmP_U;qGpPA=yF literal 0 HcmV?d00001 From 6105427789fdda3b8032c68689db3d0380f87233 Mon Sep 17 00:00:00 2001 From: David North Date: Tue, 13 Jun 2023 08:33:28 +0100 Subject: [PATCH 48/60] Upgrades to latest Tyrian, Indigo, Scala, and Mill --- VirtualGloomhavenBoard/Indigo/.mill-version | 2 +- VirtualGloomhavenBoard/Indigo/build.sc | 15 ++++---- .../src/vgb/common/BoardOverlayType.scala | 5 +-- .../Indigo/vgb-game/src/vgb/game/Main.scala | 2 +- .../components/ContextMenuComponent.scala | 4 +-- .../Indigo/vgb-ui/src/vgb/ui/Main.scala | 35 +++++++++++++------ .../Indigo/wwwroot/js/app.js | 2 +- 7 files changed, 39 insertions(+), 26 deletions(-) diff --git a/VirtualGloomhavenBoard/Indigo/.mill-version b/VirtualGloomhavenBoard/Indigo/.mill-version index 70016a7c..d9df1bbc 100644 --- a/VirtualGloomhavenBoard/Indigo/.mill-version +++ b/VirtualGloomhavenBoard/Indigo/.mill-version @@ -1 +1 @@ -0.10.12 +0.11.0 diff --git a/VirtualGloomhavenBoard/Indigo/build.sc b/VirtualGloomhavenBoard/Indigo/build.sc index a3cb2a18..cc5c01d9 100644 --- a/VirtualGloomhavenBoard/Indigo/build.sc +++ b/VirtualGloomhavenBoard/Indigo/build.sc @@ -5,9 +5,6 @@ import mill.scalajslib._ import mill.scalajslib.api._ import $file.gamedata.gameData -import $ivy.`io.github.davidgregory084::mill-tpolecat::0.3.2` -import io.github.davidgregory084.TpolecatModule - object `vgb-common` extends VgbModule object `vgb-game` extends VgbModule { @@ -49,17 +46,17 @@ object `vgb-ui` extends VgbModule { T.command { T { compile() - fastOpt() + fastLinkJS() } } } -trait VgbModule extends ScalaJSModule with TpolecatModule { - def scalaVersion = "3.2.2" +trait VgbModule extends ScalaJSModule { + def scalaVersion = "3.3.0" def scalaJSVersion = "1.13.1" - val indigoVersion = "0.14.0" - val tyrianVersion = "0.6.1" + val indigoVersion = "0.15.0-RC2" + val tyrianVersion = "0.7.1" def ivyDeps = Agg( @@ -73,7 +70,7 @@ trait VgbModule extends ScalaJSModule with TpolecatModule { override def moduleKind = T(mill.scalajslib.api.ModuleKind.CommonJSModule) - object test extends Tests with TestModule.Munit { + object test extends ScalaJSTests with TestModule.Munit { def ivyDeps = Agg( ivy"org.scalameta::munit::1.0.0-M7" diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala index 78949ae2..ec6bad1b 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala @@ -71,8 +71,9 @@ enum Treasure(val flag: Flag) extends BoardOverlayType: case Coin(val baseGame: BaseGame, val amount: Byte) extends Treasure(Flag.Coin) final case class Token(val baseGame: BaseGame, val letter: Char) extends BoardOverlayType: - val cells: Batch[Point] = Batch(Point(0, 0)) - val flag: Flag = Flag.Token + val cells: Batch[Point] = Batch(Point(0, 0)) + val flag: Flag = Flag.Token + override def toString(): String = s"""Token (${letter})""" enum Wall(val baseGame: BaseGame, val cells: Batch[Point]) extends BoardOverlayType: val flag: Flag = Flag.Wall diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala index 81ab8d2d..e1450849 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala @@ -42,7 +42,7 @@ final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) BootResult( GameConfig.default .withMagnification(magnification) - .withClearColor(RGBA.White) + .withTransparentBackground(true) .withViewport(gameViewport), gameViewport.size / magnification ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala index 78ad01f5..16706924 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala @@ -27,8 +27,8 @@ object ContextMenuComponent: overlays .filter(o => o.overlayType match { - case _: Treasure => false - case _ => true + case _: (Treasure | Token) => false + case _ => true } ) .map(o => MenuItem(s"""Rotate ${o.overlayType}""", CreatorMsgType.RotateOverlay(o.id, o.overlayType))) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala index 3920e3f3..b694804f 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala @@ -8,10 +8,13 @@ import vgb.game.{Main => VgbGame} import vgb.common.* import scala.scalajs.js.annotation.* +import scala.concurrent.duration.DurationDouble import vgb.ui.models.components.ContextMenuComponent import indigo.shared.collections.Batch enum Msg: + case NoOp + case RetryIndigo case IndigoReceive(msg: GloomhavenMsg) extends Msg case IndigoSend(msg: GloomhavenMsg) extends Msg case StartIndigo extends Msg @@ -23,6 +26,8 @@ object Main extends TyrianApp[Msg, Model]: val gameDivId = "board" val appVersion = "2.0.0-alpha" + def router: Location => Msg = Routing.none(Msg.NoOp) + def init(flags: Map[String, String]): (Model, Cmd[IO, Msg]) = (Model(), Cmd.Emit(Msg.StartIndigo)) @@ -32,17 +37,22 @@ object Main extends TyrianApp[Msg, Model]: case Msg.IndigoSend(msg) => (model, model.bridge.publish(IndigoGameId(gameDivId), msg)) case Msg.StartIndigo => - ( - model, - Cmd.SideEffect { - VgbGame(model.bridge.subSystem(IndigoGameId(gameDivId))) - .launch( - gameDivId, - "width" -> "1620", - "height" -> "800" - ) + val task: IO[Msg] = + IO { + if gameDivExists(gameDivId) then + VgbGame(model.bridge.subSystem(IndigoGameId(gameDivId))) + .launch( + gameDivId, + "width" -> "1620", + "height" -> "800" + ) + Msg.NoOp + else Msg.RetryIndigo } - ) + + (model, Cmd.Run(task)) + case Msg.RetryIndigo => + (model, Cmd.emitAfterDelay(Msg.StartIndigo, 0.25.seconds)) case Msg.CloseContextMenu => ( model.copy(sceneModel = model.sceneModel.updateContextMenu(None)), @@ -58,6 +68,7 @@ object Main extends TyrianApp[Msg, Model]: ) case None => (model, Cmd.None) } + case Msg.NoOp => (model, Cmd.None) def view(model: Model): Html[Msg] = div(id := "content", `class` := "content")( @@ -150,3 +161,7 @@ object Main extends TyrianApp[Msg, Model]: case _ => item } ) + + @SuppressWarnings(Array("scalafix:DisableSyntax.null")) + private def gameDivExists(id: String): Boolean = + document.getElementById(id) != null diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js b/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js index 6493ea8d..ddc7ebe8 100644 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js @@ -1,5 +1,5 @@ //require('@microsoft/signalr') -import * as t from '../../out/vgb-ui/fastOpt.dest/out.js'; +import * as t from '../../out/vgb-ui/fastLinkJs.dest/main.js'; t.TyrianApp.launch("main") /* const conn = new signalR From c9dceea3b40670b30bcf11cbb064b1b2f595d50d Mon Sep 17 00:00:00 2001 From: David North Date: Tue, 13 Jun 2023 08:34:08 +0100 Subject: [PATCH 49/60] Removes older assets --- .../assets/img/accordian-banner.png | Bin 11594 -> 0 bytes VirtualGloomhavenBoard/assets/img/bg.jpg | Bin 101090 -> 0 bytes VirtualGloomhavenBoard/assets/img/border.png | Bin 173231 -> 0 bytes .../assets/img/characters/icons.png | Bin 45747 -> 0 bytes VirtualGloomhavenBoard/assets/img/compass.png | Bin 20754 -> 0 bytes .../assets/img/hex-border-mask.png | Bin 445 -> 0 bytes VirtualGloomhavenBoard/assets/img/icons.png | Bin 20457 -> 0 bytes .../assets/img/page-mask.png | Bin 1853 -> 0 bytes VirtualGloomhavenBoard/assets/img/plank.jpg | Bin 14563 -> 0 bytes .../assets/scss/_board.scss | 465 ------------- .../assets/scss/_context-menu.scss | 114 ---- .../assets/scss/_creator.scss | 281 -------- VirtualGloomhavenBoard/assets/scss/_form.scss | 147 ---- .../assets/scss/_icons.scss | 94 --- .../assets/scss/_layout.scss | 635 ------------------ .../assets/scss/_mixins.scss | 26 - .../assets/scss/_modal.scss | 214 ------ .../assets/scss/_screens.scss | 327 --------- .../assets/scss/_tooltip.scss | 44 -- .../assets/scss/_tutorial.scss | 33 - VirtualGloomhavenBoard/assets/scss/main.scss | 11 - 21 files changed, 2391 deletions(-) delete mode 100644 VirtualGloomhavenBoard/assets/img/accordian-banner.png delete mode 100644 VirtualGloomhavenBoard/assets/img/bg.jpg delete mode 100644 VirtualGloomhavenBoard/assets/img/border.png delete mode 100644 VirtualGloomhavenBoard/assets/img/characters/icons.png delete mode 100644 VirtualGloomhavenBoard/assets/img/compass.png delete mode 100644 VirtualGloomhavenBoard/assets/img/hex-border-mask.png delete mode 100644 VirtualGloomhavenBoard/assets/img/icons.png delete mode 100644 VirtualGloomhavenBoard/assets/img/page-mask.png delete mode 100644 VirtualGloomhavenBoard/assets/img/plank.jpg delete mode 100644 VirtualGloomhavenBoard/assets/scss/_board.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_context-menu.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_creator.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_form.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_icons.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_layout.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_mixins.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_modal.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_screens.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_tooltip.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/_tutorial.scss delete mode 100644 VirtualGloomhavenBoard/assets/scss/main.scss diff --git a/VirtualGloomhavenBoard/assets/img/accordian-banner.png b/VirtualGloomhavenBoard/assets/img/accordian-banner.png deleted file mode 100644 index 20fc8c2e1e875eaeef13aec114666b50ff8233db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11594 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 IM6N<$f(f9u4gdfE diff --git a/VirtualGloomhavenBoard/assets/img/bg.jpg b/VirtualGloomhavenBoard/assets/img/bg.jpg deleted file mode 100644 index 84743144eaa3def287f771b5bb7d8820031b09bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101090 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ͅo#y`dD+?LS# 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 Blac@c diff --git a/VirtualGloomhavenBoard/assets/img/border.png b/VirtualGloomhavenBoard/assets/img/border.png deleted file mode 100644 index 9f89b0f58a49b52515d7294c676e574f47b483ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173231 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Ξ7Lf)(r5eUdEji3bi7 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 bqdflr?pC1vB`|LJ00000NkvXXu0mjfb&HWc diff --git a/VirtualGloomhavenBoard/assets/img/characters/icons.png b/VirtualGloomhavenBoard/assets/img/characters/icons.png deleted file mode 100644 index e08f1107a5004a1c0d08b9719ac3d7b79e60eca7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45747 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�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

g>5?KKt4HSI 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 diff --git a/VirtualGloomhavenBoard/assets/img/compass.png b/VirtualGloomhavenBoard/assets/img/compass.png deleted file mode 100644 index e23316f2fc8219b5811c4f8925deae2d0f9a994b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20754 zcmV(>K-j;DP)&i-t(&Eoin6q$rLLc}w4|-JrLVD~vag`BmyW@+qq4rLma?O=zpI?FqO`)S znYpH%w4ji|tdYH`l(wd@!K{;(jK8&?iomOwwWYGct&_Q?kGrR%x~8DEqm{a+r>UH` zzpI_Tsh_lpSY*8x~Gx0q@%>Gl)S2vys3}9sFS&;s}-pp?47tdPX5kfxA)wxf%>ri-tdgt?}X z#I26Fq>HlC+?Uy{eG2o`ps$^cs(Dnc znTofip0AdBwxpZCtCY8-j;xr2zpIkQu92{tgtVZFua0uIq@JpheYBv8uA7RvqKdPj zkgSGlw4#f%p_Za_S*n$Vz^jkIs*b2{O{Rx-!mgIBnTE-+kF0!Ou%3yro|>+ih{vy! zvY?Z(orkH9eyy5`s*rfTrirYSeyV|Ht(1JRo|mzBOs{lKqJDJ5tdFLTkguMWr-W{% zZ&Is}d7y1(rGsj!ig3H9iMpqZxTJ}ygRF~ivzB?hsf(|bdBCiXua0xHnt#2gi?Nt{ys3`Et&6~@inyVO zyrhS?q=vJbgshT$v7U*slX$nDg|?i6v6FMVp@gxNe6Nvrx}=7&kaD-1ezvBJubPCb zk9D`6f2N0T#Hxw3p@p%YgsqZxw3c?NhH9^eWVfJ#x}=H6u8gvxjHirpt&D56qlT}L zZ>ouGvzvRorHr$XZnl|sx1x)xm4LyghpLBhtA%5*jBT!lYpj=itdDuVqlLPkfVi7` zrGaa&gI=nDUagynvWsZ7lyateV5)*?$gz&4i+HhsSE7S*>2rec6wTTK4`=2P$2^o(VLDf{;R)PX|&`}*w7#<+7a{OZK|$Omp^{?n!L z!mn-qneg`Y=CR(Gj`8sHuATnu&5Qi&e!BMYq?32%-`>N5X!oGz&#wOO%EGF=oa(RS zP=IA8m^}ahO&>`_K~#9!%$RFPQ(+j#pZ9uh8;4;K4k_0n%R<8s(ajHq-Jn!Ris&MR znMFkyU5IW3eJHvULD9DwNok5MYuHs%*F`J4m|Kvk%_y@VRF(Pp*AJ`{)oMSzG^gA;DW0Kh2(5mhkA2Px#ly}tqP zLoyP#KuVNy$Bp6?L2NN1$6$nQ1P34j7pX9=H=P-qIRr8Hy8)Cn%hRflr$R48OkHIr zqKOlN;h%tzEluPcfFhBqskUCtEU7o0ppyV5FnIo*B<^}TGpTQH$)bQ+1`v4++#noG z&{wG#6NxMku)dW%(hT95=&^_!-hWuOIumrTl$nWOk4eAkSS&8F@L1D`iU?O=LVQN5 zezGJ2VM(v_F9n#iXW5%I!I)w zK_vkp#;9J^^#&1!hf}3Bk6Kjt9X&jPMVTCLq+>y51|Fm?q8MXlv@|d*q^)+9R6be> z{lVN0_L1h1V-5lAm--fSj!?9=x}>H{fxz%Fp}45Jq<#hbLAGh?l$048H=0c&LG5!C zREDDz){L3ncrgOQ>D$!csBF&bO}ZfcUR9K}cDr4fP1$%3eZm643`Ki_^(Jw6yVB{6 z4_xhT!*`n*TV`yq_pOVcp^upYa0GoYNaKtm6ooEDl&~Q;P3Dk~n(uz})#WvOH*Sy< z#*Bu3*m1x8B}HrJBl#LXZYX9jRI)-2G1FaC`=BbXS1mqc21GD1DROFt6y?2_Ax@A0 zLt-+dEI*rbIwvPjd*(DYIP2=13*(Z<26GTM3nCz7OHQrV5@cM{rC6F z9=3IM78GQ*fZ5t)iv1q}=PNyytb)-F%n zZiP|f)I=4D5Iv?1`*RAtjo%*Jxn5h;(%STM?%Y7YSJ~0hUS3*W^7!tp+hx}-IXx{E zT?PJ*Z$4+!;`KR`*Z!q3vt$E{DiD-dZNwx96z5wgL;+VmT)9$Oc!26c~LO z7cq#S%JB&)BytE&>}r2jRp<3Oz144CXA3?ml?z{P|Nmwrtt5Bd4Ri@uS1# z>L{)LRPpfUV`pVaQ)RQ;?QV4kdOSZ4uahAh+40dfXVfYPxp5|01-mUm$g*?t3d

#phQs&Daq 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 diff --git a/VirtualGloomhavenBoard/assets/img/hex-border-mask.png b/VirtualGloomhavenBoard/assets/img/hex-border-mask.png deleted file mode 100644 index 94e74fb408bd6ee40e765f35fdfc6a8030bdc50f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 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 diff --git a/VirtualGloomhavenBoard/assets/scss/_board.scss b/VirtualGloomhavenBoard/assets/scss/_board.scss deleted file mode 100644 index 458e0815..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_board.scss +++ /dev/null @@ -1,465 +0,0 @@ -@use 'mixins'; - -$hexWidth: 90px; -$hexHeight: 90px; - -.player, -.overlay, -.monster { - position: relative; - width: $hexWidth; - height: $hexHeight; - overflow: visible; - text-align: center; - - img { - height: 100%; - width: auto; - } -} - -.overlay { - width: auto; - - &.token { - width: 45px; - height: 45px; - background-color: #913a3d; - border: 3px solid #fff; - color: #fff; - border-radius: 100%; - font-size: 1.3rem; - line-height: 2.5rem; - box-shadow: 2px 1px 5px 0px rgba(0, 0, 0, 0.75); - } -} - -.hex-mask { - @include mixins.mask(url('/img/hex-mask.png'), alpha, top right, 90px); -} - -.summons:not(.bear) { - div.background { - width: 72px; - height: 73px; - display: block; - position: absolute; - top: 0.5rem; - left: 0.5rem; - border-radius: 100%; - } - - img { - position: relative; - height: 75px; - left: -1px; - top: 7px; - } - - span { - position: absolute; - top: 34px; - left: 0; - z-index: 2; - width: 100%; - color: #fff; - text-shadow: 0px 0px 4px #000; - } -} - -.treasure { - span { - position: absolute; - top: 24px; - left: 0; - font-size: 33px; - text-shadow: 0px 0px 4px #fff; - color: #353535; - display: block; - width: 100%; - } -} - -.monster { - span { - position: absolute; - top: 69px; - left: 0; - z-index: 2; - display: inline-block; - width: 100%; - } - - &.boss span { - color: #fff; - } - - &:after { - content: ""; - width: 100%; - height: 100%; - position: absolute; - display: block; - top: 0; - left: 0; - @include mixins.mask(url('/img/border-mask.png'), alpha, top right, 90px); - } - - &.normal:after { - background-color: #fff; - } - - &.elite:after { - background-color: #d9c200; - } - - &.boss:after { - background-color: #bc1717; - } -} - -.player { - &:after { - content: ""; - width: 100%; - height: 100%; - position: absolute; - display: block; - top: 0; - left: 0; - @include mixins.mask(url('/img/hex-border-mask.png'), alpha, top right, 90px); - } - - &.brute:after { - background-color: #567cc7; - } - - &.tinkerer:after { - background-color: #c0b37f; - } - - &.scoundrel:after { - background-color: #9cd750; - } - - &.cragheart:after { - background-color: #7c9427; - } - - &.mindthief:after { - background-color: #61779f; - } - - &.spellweaver:after { - background-color: #b562b8; - } - - &.diviner:after { - background-color: #84bfcf; - } - - &.phoenix-face:after, - &.bear:after { - background-color: #a96852; - } - - &.lightning-bolt:after { - background-color: #d13947; - } - - &.angry-face:after { - background-color: #60c9f4; - } - - &.triforce:after { - background-color: #9a9a9a; - } - - &.eclipse:after { - background-color: #a099d4; - } - - &.cthulhu:after { - background-color: #79ceb6; - } - - &.three-spears:after { - background-color: #d67f19; - } - - &.saw:after { - background-color: #e1dfc4; - } - - &.music-note:after { - background-color: #df6872; - } - - &.concentric-circles:after { - background-color: #b562b8; - } - - &.sun:after { - background-color: #efc024; - } - - &.envelope-x:after { - background-color: #725b4c; - } -} - -[draggable] { - -moz-user-select: none; - -khtml-user-select: none; - -webkit-user-select: none; - user-select: none; - - &[draggable="true"] { - &:hover { - cursor: move; - } - - &.being-dragged { - opacity: 0; - } - } -} - -$tiles: ( - 'a1a', - -2px, - 41px) ('a1b', -19px, 39px) ('a2a', -20px, 20px) ('a2b', -20px, 20px) ('a3a', -20px, 20px) ('a3b', -20px, 20px) ('a4a', -20px, 20px) ('a4b', -20px, 20px) ('b1a', -27px, -51px) ('b1b', -27px, -51px) ('b2a', -27px, -51px) ('b2b', -27px, -51px) ('b3a', -27px, -51px) ('b3b', -27px, -51px) ('b4a', -27px, -51px) ('b4b', -27px, -51px) ('c1a', -61px, -45px) ('c1b', -61px, -45px) ('c2a', -61px, -45px) ('c2b', -61px, -45px) ('d1a', -59px, -50px) ('d1b', -59px, -50px) ('d2a', -59px, -50px) ('d2b', -59px, -50px) ('e1a', 12px, -44px) ('e1b', 12px, -44px) ('f1a', -24px, -45px) ('f1b', -24px, -45px) ('g1a', -22px, -48px) ('g1b', -22px, -48px) ('g2a', -22px, -48px) ('g2b', -22px, -48px) ('h1a', 15px, -40px) ('h1b', 15px, -40px) ('h2a', 15px, -40px) ('h2b', 15px, -40px) ('h3a', 15px, -40px) ('h3b', 15px, -40px) ('i1a', -25px, -47px) ('i1b', -25px, -47px) ('i2a', -25px, -47px) ('i2b', -25px, -47px) ('j1a', -25px, -51px) ('j1b', -24px, -49px) ('j1ba', -24px, -49px) ('j1bb', -24px, -49px) ('j2a', -25px, -52px) ('j2b', -24px, -49px) ('k1a', -56px, -47px) ('k1b', -71px, -47px) ('k2a', -73px, -45px) ('k2b', -56px, -47px) ('l1a', -25px, -47px) ('l1b', -25px, -47px) ('l2a', -25px, -47px) ('l2b', -25px, -47px) ('l3a', -25px, -47px) ('l3b', -25px, -47px) ('m1a', -20px, -45px) ('m1b', -22px, -46px) ('n1a', -19px, -48px) ('n1b', -19px, -48px -); - -.mapTiles { - position: relative; - - .mapTile { - position: absolute; - width: 75px; - height: $hexHeight; - overflow: visible; - - @for $i from 1 through 5 { - &.rotate-#{$i} { - transform: rotate(60deg * $i ); - } - } - - img { - position: relative; - transition: opacity 1s; - - @each $tile in $tiles { - $key: nth($tile, 1); - $left: nth($tile, 2); - $top: nth($tile, 3); - - &.ref-#{$key} { - left: $left; - top: $top; - } - } - } - - &.outline { - img { - opacity: 0.08; - } - } - - - &.hidden img { - opacity: 0; - } - } -} - -.board { - text-align: center; - - .row { - display: flex; - flex-direction: row; - position: relative; - - @for $var from 2 through 100 { - &:nth-child(#{$var}) { - top: -(23px * ($var - 1)); - } - } - - &:nth-child(even) { - left: 38px; - } - - .cell-wrapper { - position: relative; - overflow: visible; - visibility: visible; - transition: opacity 1s; - - &.hidden { - opacity: 0; - visibility: hidden; - } - - .cell { - width: 76px; - height: 90px; - position: relative; - z-index: 1; - overflow: visible; - - .hexagon { - width: 90px; - height: 90px; - position: relative; - left: -7px; - touch-action: none; - - >div { - position: absolute; - top: 0; - left: 0; - } - - .monster, - .player { - &.out-of-phase { - opacity: 0.5; - } - - &:not(:only-child) { - transform-origin: left; - transform: scale(0.85); - } - } - - .overlay { - &.token { - transform: scale(0.5); - right: 0; - left: auto; - top: 40px; - - &:first-child { - transform: scale(1); - top: 22px; - left: 21px; - } - } - - &.highlight { - width: 100%; - height: 100%; - position: absolute; - display: block; - top: 0; - left: 0; - animation-duration: 0.75s; - animation-name: pulse; - animation-iteration-count: infinite; - animation-direction: alternate; - @include mixins.mask(url('/img/hex-border-mask-thick.png'), alpha, top right, 90px); - - div { - width: 100%; - height: 100%; - } - - &+.token { - transform: scale(1); - top: 22px; - left: 21px; - } - - &+.coin { - transform: scale(1); - top: 0; - left: 0; - } - } - - &.start-location { - - &+.monster, - &+.player { - transform: scale(1); - } - - &+.token { - transform: scale(1); - top: 22px; - left: 21px; - } - } - - &.diagonal-right { - transform: rotate(120deg); - } - - &.diagonal-right-reverse { - transform: rotate(300deg); - } - - &.diagonal-left { - transform: rotate(60deg); - } - - &.diagonal-left-reverse { - transform: rotate(240deg); - } - - &.horizontal { - transform: rotate(180deg); - } - - &.treasure { - transform: scale(0.5); - left: 20px; - top: 20px; - - &[data-index]:after { - content: attr(data-index); - display: block; - position: absolute; - top: 10px; - left: 0; - width: 100%; - } - - &:first-child { - transform: scale(1); - left: 0; - top: 0; - } - } - - &.corridor+.treasure { - transform: scale(1); - left: 0; - top: 0; - } - - img { - width: auto; - height: 100%; - } - } - } - } - } - - } -} - -@keyframes pulse { - from { - transform: scale(0.95); - } - - to { - transform: scale(1.05); - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_context-menu.scss b/VirtualGloomhavenBoard/assets/scss/_context-menu.scss deleted file mode 100644 index e8cee61f..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_context-menu.scss +++ /dev/null @@ -1,114 +0,0 @@ -.context-menu { - position: absolute; - border-image: url('/img/border.png') 0 fill; - background-color: transparent; - border-style: solid; - padding: 1.4rem; - z-index: 1; - opacity: 0; - transition: opacity 0.3s; - visibility: hidden; - width: 14rem; - transition: 0.15s opacity; - - &.open { - opacity: 1; - visibility: visible; - } - - nav { - ul { - list-style: none; - padding: 0; - margin: 0.8rem 0 0 0; - - li { - padding: 0.2rem 1rem; - border-radius: 0.2rem; - position: relative; - - &:hover { - cursor: pointer; - background-color: rgba(0, 0, 0, 0.2) - } - - &.has-sub-menu { - &:after { - content: '\25BA'; - font-size: 0.6rem; - position: absolute; - right: 0.6rem; - top: 0.4rem; - } - - div { - visibility: hidden; - position: absolute; - right: -7.1rem; - border-image: url('/img/border.png') 0 fill; - background-color: transparent; - border-style: solid; - padding: 1.4rem; - z-index: 2; - top: -0.9rem; - border-radius: 0.2rem; - max-height: 15rem; - - ul { - max-height: 11rem; - overflow-y: auto; - min-width: 5rem; - - li { - padding: 0.2rem 1.3rem; - - &:hover { - cursor: pointer; - background-color: rgba(0, 0, 0, 0.2) - } - - &.selected { - &:after { - content: '\2713'; - font-size: 1.1rem; - position: absolute; - left: 0rem; - top: 0.2rem; - } - } - } - } - } - - &:hover { - div { - visibility: visible; - } - } - } - - &.cancel { - display: none; - } - - &.cancel-menu, - ul li.cancel-menu, - &:not([class^="remove"])+[class^="remove"] { - margin-top: 0.7rem; - - &:before { - content: " "; - display: block; - height: 1px; - width: 75%; - border: 1px solid #888; - background-color: #333; - position: absolute; - left: 1rem; - top: -0.4rem; - } - } - } - } - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_creator.scss b/VirtualGloomhavenBoard/assets/scss/_creator.scss deleted file mode 100644 index a6232999..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_creator.scss +++ /dev/null @@ -1,281 +0,0 @@ -@use 'mixins'; - -html -{ - .content.scenario-creator { - header { - .title { - input { - text-align: center; - font-size: 2rem; - color: #aaa; - text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - font-family: "PirateOne", Nyala, Georgia, serif; - background-color: transparent; - border: none; - outline: none; - width: 38rem; - - &:focus { - outline: grey solid 1px; - } - - &::placeholder { - opacity: 1; - } - } - } - } - .main { - .page-shadow { - height: 100%; - width: 1rem; - -webkit-box-shadow: 5px 0px 15px 9px rgba(0,0,0,0.65); - -moz-box-shadow: 5px 0px 15px 9px rgba(0,0,0,0.65); - box-shadow: 18px 0px 35px 9px rgb(0, 0, 0); - position: absolute; - left: 7.1rem; - z-index: 1; - } - - .action-list { - flex-direction: column; - flex-wrap: nowrap; - align-items: center; - justify-content: flex-start; - padding-bottom: 1rem; - width: 10.5rem; - @include mixins.mask(url('/img/page-mask.png'), alpha, top right); - @include mixins.mask-repeat(repeat-y); - - section { - display: flex; - flex-direction: column; - min-height: 0; - flex-basis: 4rem; - width: 100%; - transition: flex-basis 0.25s; - - header { - flex-basis: 1rem; - padding: 0.2rem 0 0.75rem 1rem; - background-image: url('/img/accordian-banner.png'); - background-repeat: no-repeat; - background-size: cover; - background-position-y: -0.5rem; - color: #fff; - - &:before { - content: ''; - display: block; - position: absolute; - width: 100%; - height: 1.7rem; - -webkit-box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.75); - -moz-box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.75); - box-shadow: 0px 2px 10px 0px rgba(0,0,0,0.75); - left: 0; - z-index: -1; - } - - &:hover { - cursor: pointer; - } - } - - ul { - list-style: none; - visibility: hidden; - margin: 0; - padding: 0; - overflow: hidden; - -webkit-box-shadow: inset 0px -5px 5px 0px rgba(0,0,0,0.75); - -moz-box-shadow: inset 0px -5px 5px 0px rgba(0,0,0,0.75); - box-shadow: inset 0px -5px 5px 0px rgba(0,0,0,0.75); - width: 9.6rem; - text-align: center; - - li { - padding: 0.2rem 1.2rem; - - img { - max-width: 45px; - } - - .token { - transform: scale(0.85); - top: 0; - left: 33px; - } - - &.size-3 { - img { - position: relative; - - &:first-child, &:nth-child(2) { - top: 31px; - } - - &:last-child { - top: -66px; - } - } - } - } - - &.map-tiles { - li { - img { - max-width: 90px; - } - } - } - - &.monsters { - li { - div.monster { - position: relative; - max-width: 45px; - @include mixins.mask(null, null, null, 45px); - height: auto; - display: inline-block; - - &:after { - display: none; - } - - img { - max-width: 45px; - height: auto; - } - - span { - display: none; - } - } - } - } - } - - &.active { - flex-basis: 100%; - - ul { - overflow-y: scroll; - visibility: visible; - } - } - } - } - - .board-wrapper { - margin-left: 9.5rem; - - .board { - .monster { - span { - display: none; - } - - .monster-visibility { - position: absolute; - width: 35px; - height: 35px; - - &.two-player { - top: 0px; - left: -15px; - transform: rotate(32deg); - } - - &.three-player { - top: 3px; - transform: rotate(61deg); - right: -17px; - } - - &.four-player { - bottom: -23px; - left: 27px; - } - - &.normal { - background-color: #fff; - } - - &.none { - background-color: #000; - } - - &.elite { - background-color: #d9c200; - } - } - - - &.boss { - .monster-visibility { - display: none; - } - } - - &:after { - background-color: #bc1717; - } - - &:not(.boss):after { - @include mixins.mask(url('/img/hex-border-mask.png'), alpha, top right, 90px); - } - } - - .room-origin { - width: 76px; - height: 90px; - position: absolute; - top: -1.3rem; - transform: scale(0.5); - left: -1.1rem; - z-index: 1; - - &:hover { - cursor: move; - } - - &:after { - content: " "; - width: 76px; - height: 90px; - display: block; - background-image: url('/img/arrows-alt-solid.svg'); - background-repeat: no-repeat; - background-size: 60%; - background-position: center; - position: absolute; - top: 0; - } - - &:before { - content: " "; - width: 76px; - height: 90px; - display: block; - background-image: url('/img/hex-mask.png'); - background-repeat: no-repeat; - background-size: 100%; - background-position: center; - filter: brightness(50); - } - - &.dragging { - opacity: 0; - - &:before, &:after { - opacity: 0; - } - } - } - } - } - } - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_form.scss b/VirtualGloomhavenBoard/assets/scss/_form.scss deleted file mode 100644 index 1c7b66d1..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_form.scss +++ /dev/null @@ -1,147 +0,0 @@ -.input-wrapper { - display: flex; - flex-direction: column; - margin-bottom: 1.6rem; - position: relative; - - label { - font-size: 1.3rem; - padding-bottom: 0.3rem; - } - - input:not([type="checkbox"]) { - border-radius: 0; - background-color: rgba(0, 0, 0, 0); - border-color: #000; - border-width: 1px; - padding: 0.4rem; - font-size: 1.1rem; - outline: none; - background-color: rgba(49,40,38, 0.7); - color: #aaa; - - &:focus { - border-color: #ccc; - -webkit-box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.75); - -moz-box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.75); - box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.75); - } - } - - label { - position: relative; - - input[type="color"] { - padding: 0; - width: 1.5rem; - float: right; - } - - &.checkbox { - cursor: pointer; - - input[type="checkbox"] { - visibility: hidden; - } - - &:before { - content: ''; - width: 1rem; - height: 1rem; - display: block; - border: 2px solid #563e25; - position: absolute; - top: 0.1rem; - right: 0; - } - - &:after { - content: ""; - width: 16px; - height: 16px; - display: block; - position: absolute; - top: 0.1rem; - right: 0; - box-sizing: content-box; - background-image: url('/img/icons.png'); - background-size: 128px; - background-position: -72px -24px; - transform: scale(1.4); - filter: grayscale(20%); - opacity: 0; - transition: 0.2s; - } - - &.checked:after { - opacity: 1; - } - } - } - - &.error { - .error-label { - position: absolute; - font-family: Arial, Helvetica, sans-serif; - letter-spacing: 0; - line-height: 1.5rem; - text-shadow: 0 0; - font-weight: bold; - color: red; - bottom: -1.4rem; - overflow: hidden; - text-overflow: ellipsis; - max-height: 1.3rem; - max-width: 100%; - } - } -} - -.select-wrapper { - display: flex; - flex-direction: column; - margin-bottom: 1.6rem; - position: relative; - - label { - font-size: 1.3rem; - padding-bottom: 0.3rem; - } - - select { - border-radius: 0; - background-color: rgba(0, 0, 0, 0); - border-color: #000; - border-width: 1px; - padding: 0.4rem; - font-size: 1.1rem; - outline: none; - background-color: rgba(49,40,38, 0.7); - color: #aaa; - - &:focus { - border-color: #ccc; - -webkit-box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.75); - -moz-box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.75); - box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.75); - } - } -} - -.button-wrapper { - display: flex; - justify-content: space-between; - align-items: center; - - button { - border-radius: 0; - border-radius: 0; - font-size: 1rem; - padding: 10px; - width: 80px; - border: 2px solid #604729; - background: #a68f7a; - color: #93292e; - font-family: "PirateOne", Nyala, Georgia, serif; - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_icons.scss b/VirtualGloomhavenBoard/assets/scss/_icons.scss deleted file mode 100644 index 813bd5e9..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_icons.scss +++ /dev/null @@ -1,94 +0,0 @@ -i { - display: inline-block; - font-size: 0; - text-indent: -99999em; - margin-right: 1rem; - height: 4.5rem; - - &.icon { - &:before { - content: ""; - display: block; - width: 45px; - height: 45px; - background-image: url("/img/characters/icons.png"); - background-size: 256px; - filter: contrast(0%) brightness(130%) drop-shadow(1px 1px black); - top: 0.7rem; - position: relative; - } - - &.brute:before { - background-position: -90px 1px; - top: 0.4rem; - } - - &.tinkerer:before { - background-position: -45px -90px; - } - - &.scoundrel:before { - background-position: -135px -90px; - } - - &.cragheart:before { - background-position: -45px -135px; - } - - &.mindthief:before { - background-position: 0 -45px; - } - - &.spellweaver:before { - background-position: -135px -45px; - } - - &.diviner:before { - background-position: -90px -135px; - } - - &.phoenix-face:before { - background-position: 0 0; - } - - &.lightning-bolt:before { - background-position: -45px 0; - } - - &.angry-face:before { - background-position: -135px 0; - } - - &.triforce:before { - background-position: -180px 0; - } - - &.eclipse:before { - background-position: -45px -45px; - } - - &.cthulhu:before { - background-position: -90px -45px; - } - - &.three-spears:before { - background-position: 0 -135px; - } - - &.saw:before { - background-position: -180px -90px; - } - - &.music-note:before { - background-position: -90px -90px; - } - - &.concentric-circles:before { - background-position: -180px -45px; - } - - &.sun:before { - background-position: 0 -90px; - } - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_layout.scss b/VirtualGloomhavenBoard/assets/scss/_layout.scss deleted file mode 100644 index a51d2482..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_layout.scss +++ /dev/null @@ -1,635 +0,0 @@ -@use 'mixins'; - -@font-face { - font-family: 'PirateOne'; - src: url('/fonts/PirataOne-Gloomhaven.eot'); - src: url('/fonts/PirataOne-Gloomhaven.woff2') format('woff2'), url('/fonts/PirataOne-Gloomhaven.woff') format('woff'), url('/fonts/PirataOne-Gloomhaven.ttf') format('truetype'), url('/fonts/PirataOne-Gloomhaven.svg') format('svg'); -} - -:root { - font-size: 1rem; -} - -html { - font-family: 'PirateOne', Nyala, Georgia, serif; - - &, - body { - margin: 0; - padding: 0; - height: 100vh; - width: 100vw; - overflow: hidden; - } - - * { - box-sizing: border-box; - } - - - a { - text-decoration: none; - color: #fff; - transition: 0.5s; - - &:hover { - color: #be514f; - } - } - - .content { - display: flex; - width: 100vw; - flex-direction: column; - height: 100vh; - - .cell-details { - top: 0; - left: -2px; - width: 1px; - height: 1px; - position: absolute; - overflow: hidden; - } - - .header { - position: absolute; - display: flex; - background-image: url('/img/plank.jpg'); - border-bottom: 1px solid black; - box-shadow: 0 5px 40px 0 black; - background-size: contain; - z-index: 4; - height: 3.4rem; - top: 0; - transition: top 0.2s; - width: 100%; - - .menu { - &:before { - content: ""; - color: #ccc; - text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - cursor: pointer; - position: relative; - left: 1rem; - top: 0.3rem; - font-family: serif; - display: block; - width: 45px; - height: 45px; - background-image: url("/img/icons.png"); - background-size: 256px; - background-position: -90px -45px; - filter: invert(100%) drop-shadow(2px 1px 0 black); - transition: 0.2s; - z-index: 5; - } - - nav { - position: absolute; - z-index: 4; - opacity: 0; - visibility: hidden; - transition: 0.3s; - background-image: url('/img/plank.jpg'); - border: 2px solid #222; - background-size: 190%; - top: 4rem; - left: 1.2rem; - font-size: 1.4rem; - color: #aaa; - text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - padding: 1rem; - border-radius: 0.5rem; - - &:after { - content: ''; - border: solid #222; - border-width: 0 3px 3px 0; - display: inline-block; - padding: 0.2rem; - transform: rotate(225deg); - width: 0.3rem; - position: absolute; - left: 0.7rem; - height: 0.3rem; - top: -0.5rem; - background-image: url("/img/plank.jpg"); - } - - ul { - list-style: none; - padding: 0; - margin: 0; - - li { - cursor: pointer; - margin-bottom: 0.4rem; - position: relative; - padding-right: 3.1rem; - - .shortcut { - font-family: Arial, Helvetica, sans-serif; - position: absolute; - right: -0.9rem; - display: flex; - top: 0; - font-size: 0.7rem; - - .key { - padding: 0.3rem 0.3rem; - display: inline-block; - border: 1px solid black; - margin-right: 0.2rem; - text-align: center; - background-color: rgba(128, 128, 128, 0.5); - color: white; - border-radius: 4px; - transition: 0.2s; - min-width: 1.5rem; - } - } - - a { - color: #aaa; - display: inline-block; - width: 100%; - transition: 0s; - } - - a:hover, - &:hover { - color: #fff; - - .shortcut { - .key { - background-color: rgba(128, 128, 128, 1); - } - } - } - - &.section-end { - &:after { - content: ""; - width: 100%; - background-color: #333; - border-bottom: 1px solid #666; - height: 1px; - display: block; - position: absolute; - bottom: -5px; - } - - margin-bottom: 0.65rem; - } - } - } - } - - &.show { - &:before { - filter: invert(75%) drop-shadow(2px 1px 0 black); - } - - nav { - opacity: 1; - visibility: visible; - } - } - } - - header { - flex: 1; - text-align: center; - align-self: center; - font-size: 2rem; - color: #aaa; - text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - position: relative; - - .number { - margin-right: 1rem; - - &:before { - content: '# '; - speak: never; - } - - &:empty { - &:before { - display: none; - } - } - } - } - - .roomCode { - font-size: 1.1rem; - color: #aaa; - text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - display: flex; - flex-direction: column; - padding: 0.3rem 2rem 0 0; - - span { - &:last-child { - font-family: Arial, Helvetica, sans-serif; - speak-as: literal-punctuation; - } - } - } - } - - .main { - flex: 1; - position: relative; - overflow: hidden; - display: flex; - margin-top: 3.4rem; - margin-bottom: 4.01rem; - transition: margin-top 0.2s, margin-bottom 0.2s; - - .action-list { - flex-grow: 1; - flex-shrink: 0; - height: 100%; - display: flex; - position: absolute; - overflow: visible; - background-image: url("/img/bg.jpg"); - box-shadow: 10px 0px 40px 10px rgba(0, 0, 0, 0.75); - z-index: 2; - left: 0; - width: 9.2rem; - transition: left 0.2s; - - .side-toggle { - width: 2.5rem; - height: 3rem; - position: absolute; - top: 50vh; - right: -2.5rem; - bottom: 50vh; - background-image: url('/img/plank.jpg'); - display: none; - transition: right 0.5s; - - &:before { - content: '>'; - color: white; - display: block; - font-family: serif; - line-height: 2.9rem; - font-size: 1.3rem; - text-align: center; - font-weight: bold; - } - } - - &.show { - .side-toggle { - &:before { - content: '<'; - } - } - } - - .sidebar-wrapper { - z-index: 3; - box-shadow: 25px 0px 25px -5px rgba(0, 0, 0, 0.75); - margin-right: 15px; - width: 85px; - - nav { - width: 110px; - height: 100%; - overflow: hidden; - background-image: url("/img/bg.jpg"); - background-repeat: repeat; - background-attachment: local; - @include mixins.mask(url('/img/page-mask.png'), alpha, top right); - @include mixins.mask-repeat(repeat-y); - - ul { - list-style: none; - padding: 0 0 0 17px; - margin: 0; - height: 100%; - width: 90px; - overflow: auto; - overflow-x: hidden; - scrollbar-width: thin; - - li { - display: inline-block; - padding: 5px 10px; - transition: all 0.25s; - background-image: url('/img/icons.png'); - font-size: 0; - text-indent: -9999rem; - width: 45px; - height: 45px; - background-size: 256px; - cursor: pointer; - - &:hover { - filter: drop-shadow(0 0 5px #aaa); - } - - &.active { - filter: drop-shadow(0 0 5px #93292e); - } - - &.move-piece { - background-position: -45px -45px; - } - - &.kill-piece { - background-position: -135px 0; - } - - &.loot { - background-position: 0 -45px; - } - - &.move-overlay { - background-position: -180px 0; - } - - &.destroy-overlay { - background-position: -45px 0; - } - - &.reveal-room { - background-position: 0 0; - } - - &.add-piece { - background-position: -90px 0; - } - } - } - } - } - - .new-piece-wrapper { - width: 110px; - margin-left: -100px; - height: 100%; - overflow: hidden; - box-shadow: 50px 0px 40px 10px rgba(0, 0, 0, 0.75); - margin-right: 9px; - transition: 0.5s; - overflow: visible; - - &.show { - margin-left: 10px; - box-shadow: 49px 0px 40px 10px rgba(0, 0, 0, 0.75); - - .new-piece-list { - ul { - overflow: auto; - overflow-x: hidden; - } - } - - &+.side-toggle { - right: -10.1rem; - } - } - - .new-piece-list { - height: 100%; - width: 140px; - @include mixins.mask(url('/img/page-mask.png'), alpha, bottom right); - @include mixins.mask-repeat(repeat-y); - padding-right: 16px; - background-image: url("/img/bg.jpg"); - background-repeat: repeat; - background-attachment: local; - - ul { - list-style: none; - width: 120px; - padding: 0; - margin: 0; - height: 100%; - overflow: hidden; - overflow-x: hidden; - background-image: url("/img/bg.jpg"); - background-repeat: repeat; - background-attachment: local; - scrollbar-width: thin; - - li { - display: inline-block; - padding: 5px 10px; - - [draggable] { - transition: opacity 0.2s; - - &.being-dragged { - visibility: visible; - opacity: 0.5; - } - } - } - } - } - } - } - - .board-wrapper { - height: 100%; - width: 100%; - overflow: auto; - background-image: radial-gradient(circle, rgba(241, 236, 232, 0.5) 31%, rgba(156, 124, 108, 0.3) 85%, rgba(81, 64, 30, 0.1) 100%), url("/img/bg.jpg"); - background-repeat: repeat; - background-attachment: local; - scrollbar-width: thin; - position: relative; - padding: 40px; - - .map-bg { - position: absolute; - top: 0; - right: -175px; - background-image: url('/img/compass.png'); - width: 175px; - height: 254px; - opacity: 0.55; - } - } - - .connectionStatus, - .errorStatus { - position: absolute; - left: 50%; - right: 50%; - width: 27rem; - background-color: #a6192b; - padding: 0.5rem 1rem; - display: flex; - justify-content: space-between; - transform: translate(-50%, 0); - font-size: 1.4rem; - transition: top 0.5s; - top: -3rem; - -webkit-box-shadow: -1px 3px 5px 0px rgba(0, 0, 0, 0.75); - -moz-box-shadow: -1px 3px 5px 0px rgba(0, 0, 0, 0.75); - box-shadow: -1px 3px 5px 0px rgba(0, 0, 0, 0.75); - z-index: 1; - - span { - display: inline-block; - width: 100%; - max-height: 2rem; - text-overflow: ellipsis; - overflow: hidden; - } - - &.show { - top: 0; - } - - &:before, - &:after { - content: ''; - width: 4rem; - height: 2.9rem; - position: absolute; - top: -1rem; - background-color: #a6192b; - z-index: -1; - } - - &:before { - transform: rotate(45deg); - left: -2.4rem; - } - - &:after { - transform: rotate(-45deg); - right: -2.4rem; - } - - a { - font-family: Arial, Helvetica, sans-serif; - font-size: 1rem; - line-height: 1.8rem; - cursor: pointer; - } - } - } - - footer { - font-family: Arial, Helvetica, sans-serif; - display: flex; - align-items: center; - justify-content: space-between; - color: #aaa; - text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - font-size: 0.75rem; - background-image: url("/img/plank.jpg"); - background-size: contain; - border-top: 1px solid black; - box-shadow: 0 -5px 40px 0 black; - z-index: 4; - position: absolute; - bottom: 0; - width: 100%; - height: 4rem; - transition: bottom 0.2s; - - .credits { - display: flex; - flex-direction: column; - padding: 1rem; - - .gloomCopy { - margin-bottom: 0.4rem; - } - } - - .pkg { - padding: 1rem; - display: flex; - ; - flex-wrap: wrap; - justify-content: end; - - .copy-wrapper { - width: 100%; - display: flex; - text-align: right; - align-items: center; - position: relative; - justify-content: flex-end; - margin-bottom: 0.3rem; - - .sponsor { - position: relative; - - .sponsor-button { - height: 35px; - width: 128px; - display: block; - border: none; - transform: scale(.65); - } - } - } - - .version { - width: 100%; - padding-right: 1.7rem; - position: relative; - top: -0.4rem; - text-align: right; - - a { - margin-right: 10.3rem; - } - } - } - } - - &.board-only { - .header { - top: -3.4rem; - - .menu { - &:before { - top: 4rem; - } - - nav { - top: 7.5rem; - } - } - } - - .main { - margin-top: 0; - margin-bottom: 0; - - .action-list { - left: - 9.2rem; - - .new-piece-wrapper { - display: none; - } - } - - .board-wrapper { - margin-left: 0; - } - } - - footer { - bottom: -4rem; - } - } - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_mixins.scss b/VirtualGloomhavenBoard/assets/scss/_mixins.scss deleted file mode 100644 index 9b7fb2d0..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_mixins.scss +++ /dev/null @@ -1,26 +0,0 @@ -@mixin mask($url, $type: null, $position: null, $size: null) { - @if ($url) { - -webkit-mask-image: $url; - mask-image: $url; - } - - @if ($type) { - -webkit-mask-type: $type; - mask-type: $type; - } - - @if ($position) { - -webkit-mask-position: $position; - mask-position: $position; - } - - @if ($size) { - -webkit-mask-size: $size; - mask-size: $size; - } -} - -@mixin mask-repeat($repeat) { - -webkit-mask-repeat: $repeat; - mask-repeat: $repeat; -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_modal.scss b/VirtualGloomhavenBoard/assets/scss/_modal.scss deleted file mode 100644 index e9305e11..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_modal.scss +++ /dev/null @@ -1,214 +0,0 @@ -.overlay-dialog { - position: fixed; - top: 0; - left: 0; - background-color: rgba(0,0,0, 0.5); - width: 100vw; - height: 100vh; - display: flex; - justify-content: center; - align-items: center; - z-index: 100; - opacity: 0; - animation-duration: 0.5s; - animation-name: fadeIn; - animation-fill-mode: both; - - .dialog { - padding: 45px; - color: #aaa; - text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; - border-image: url('/img/border.png') 0 fill; - background-color: transparent; - border-style: solid; - transform: scaleX(0); - animation-delay: 0.55s; - animation-duration: 0.5s; - animation-name: unroll; - animation-fill-mode: both; - letter-spacing: 0.1rem; - min-width: 20rem; - - .scenario-form { - input[type="number"] { - text-align: center; - } - - .file-choose { - flex-direction: column; - align-items: flex-start; - - button { - width: 100px; - } - - span { - order: -1; - margin: 0.5rem 0; - } - } - } - - .client-form { - .split-input { - input { - max-width: 5.6rem; - text-align: center; - speak-as: spell-out; - } - - span { - margin: 0 0.95rem; - font-size: 1.2rem; - font-weight: bold; - } - } - } - - .character-form { - display: flex; - width: 75vw; - max-width: 810px; - flex-wrap: wrap; - padding: 1rem 5.3rem; - - .input-wrapper { - label { - font-size: 0; - text-indent: -99999em; - width: 90px; - height: 90px; - background-image: url('/img/characters/icons.png'); - background-size: 512px; - filter: contrast(0%) brightness(70%); - transition: filter 0.25s, transform 0.15s; - position: relative; - cursor: pointer; - - &.brute { - background-position: -180px 1px; - } - - &.tinkerer { - background-position: -90px -180px; - } - - &.scoundrel { - background-position: -270px -180px; - } - - &.cragheart { - background-position: -90px -270px; - } - - &.mindthief { - background-position: 0 -90px; - } - - &.spellweaver { - background-position: -270px -90px; - } - - &.diviner { - background-position: -180px -270px; - } - - &.phoenix-face { - background-position: 0 0; - } - - &.lightning-bolt { - background-position: -90px 0; - } - - &.angry-face { - background-position: -270px 0; - } - - &.triforce { - background-position: -360px 0; - } - - &.eclipse { - background-position: -90px -90px; - } - - &.cthulhu { - background-position: -180px -90px; - } - - &.three-spears { - background-position: 0 -269px; - } - - &.saw { - background-position: -360px -180px; - } - - &.music-note { - background-position: -180px -180px; - } - - &.concentric-circles { - background-position: -360px -90px; - } - - &.sun { - background-position: 0 -179px; - } - - &.envelope-x { - background-position: -270px -270px; - } - - &.selected { - filter: contrast(100%) brightness(100%) drop-shadow(1px 1px black); - } - - &:hover { - transform: scale(1.1); - } - - input[type="checkbox"] { - visibility: hidden; - } - } - } - - .button-wrapper { - width: 100%; - flex-shrink: 0; - } - } - } -} - -@keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} - -@keyframes unroll { - from { - transform: scaleX(0); - } - - to { - transform: scaleX(1); - } -} - -@keyframes popIn { - from { - transform: scale(0); - } - - to { - transform: scale(1); - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_screens.scss b/VirtualGloomhavenBoard/assets/scss/_screens.scss deleted file mode 100644 index 0d262bf3..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_screens.scss +++ /dev/null @@ -1,327 +0,0 @@ -@media - // Extra small devices (portrait phones, less than 576px) - (max-width: 575px), - // Small devices (landscape phones, 576px and up) - (max-width: 767px) { - :root { - font-size: 0.9rem; - } - - html { - i { - &.icon { - height: 5.4rem; - - &:before { - transform: scale(0.75); - top: 1rem; - } - - &.brute:before { - top: 0.9rem; - } - } - } - - .content { - .header { - header { - font-size: 1.5rem; - - .title { - input { - width: 50%; - } - } - } - - .roomCode { - display: none; - } - - .menu { - nav { - ul { - li { - .shortcut { - display: none; - } - } - } - } - } - } - - .main { - margin-bottom: 0; - - .action-list { - .side-toggle { - display: block; - } - - .new-piece-wrapper { - .new-piece-list { - ul { - li { - transform: scale(0.8); - transform-origin: top; - - :first-child { - margin-top: 1rem; - } - - &:not(:first-child) { - margin: -1.3rem 0; - } - - .summons { - span { - line-height: 3.5rem; - } - } - } - } - } - } - } - - .board-wrapper { - margin-left: 0; - - .map-bg { - display: none; - } - - .mapTiles, .board { - transform: scale(0.8); - transform-origin: top; - } - } - - .action-list.show { - & + .board-wrapper { - margin-left: 9.2rem; - } - } - - .connectionStatus { - width: 75vw; - font-size: 1rem; - height: 3rem; - - a { - line-height: 1.2rem; - } - } - } - - .context-menu { - &, li ul { - width: 110%; - height: 110%; - position: absolute; - top: -5% !important; - left: -5% !important; - padding: 2.8em 2em; - font-size: 1.5em; - transition: 0.25s left, 0.25s opacity; - z-index: 2; - } - - li.has-sub-menu { - position: initial; - - ul { - left: 95% !important; - padding: 3.8em 2em; - font-size: 1em; - overflow: auto; - - &.open { - visibility: visible; - } - } - } - - &.sub-menu-open { - left: -110% !important - } - - .cancel { - display: block; - } - } - - footer { - display: none; - } - - &.scenario-creator { - .main { - .board-wrapper { - margin-left: 8rem; - } - } - } - } - - .tutorial { - display: none; - } - - .overlay-dialog { - .dialog { - border: none; - width: 100vw; - height: 100vh; - background-image: radial-gradient(circle, rgba(241, 236, 232, 0.3) 31%, rgba(156, 124, 108, 0.4) 85%, rgba(81, 64, 30, 0.3) 100%), url("/img/bg.jpg"); - display: flex; - align-items: center; - overflow-x: scroll; - padding: 1.2rem; - - & > div { - width: 100%; - } - - .character-form { - width: 100%; - padding: 0; - justify-content: center; - - .button-wrapper { - width: 100%; - } - } - } - } - } - } - - -// Medium devices (tablets, 768px and up) -@media (max-width: 991px) { - -} - -// 4k+ -@media (min-width: 2800px) { - :root { - font-size: 1.5rem; - } - - html { - i { - &.icon { - height: 2.6rem; - - &:before { - top: 0.2rem; - } - - &.brute:before { - top: 0.1rem; - } - } - } - - .content { - .header { - .menu { - &:before { - transform: scale(1.5); - transform-origin: top; - } - } - } - - .main { - .board-wrapper { - padding-left: 8rem; - transform: scale(1.25); - transform-origin: top left; - - .overlay { - &.token { - line-height: 1.5rem; - } - } - } - } - - footer { - .pkg { - .copy-wrapper { - .sponsor { - .sponsor-button { - transform: scale(0.85); - } - } - } - - .version { - a { - margin-right: 7.6rem; - } - } - } - } - - &.scenario-creator { - .main { - .action-list { - width: 10.2rem; - transform: scale(1.25); - transform-origin: top left; - padding-bottom: 16rem; - - section { - ul { - li { - padding: 0.2rem 2.2rem; - } - } - } - } - } - } - } - - .summons { - span { - font-size: 0.75rem; - } - } - - .monster { - span { - font-size: 0.75rem; - } - } - - .tutorial { - &.step-2 { - top: 4rem; - } - } - - .input-wrapper { - label { - &.checkbox { - &::after { - top: 0.3rem; - right: 0.2rem; - } - } - - input { - &[type="color"] { - width: 1.3rem; - height: 1.3rem; - } - } - } - } - } -} diff --git a/VirtualGloomhavenBoard/assets/scss/_tooltip.scss b/VirtualGloomhavenBoard/assets/scss/_tooltip.scss deleted file mode 100644 index fd88d447..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_tooltip.scss +++ /dev/null @@ -1,44 +0,0 @@ -html { - .tooltip-wrapper { - position: absolute; - z-index: 2; - color: white; - background-color: rgba(0, 0, 0); - padding: 0.4rem; - margin-left: 1rem; - letter-spacing: 0.12rem; - transition: all 0.2s; - opacity: 0; - animation-duration: 0.5s; - animation-name: tooltipIn; - animation-fill-mode: both; - animation-delay: 0.75s; - - &:after { - width: 0.75rem; - height: 0.75rem; - content: ''; - display: block; - position: absolute; - left: -0.35rem; - transform: rotate(45deg); - z-index: 1; - background-color: rgba(0, 0, 0); - top: 0.7rem; - } - - .tooltip-text { - padding-left: 0.5rem; - } - } -} - -@keyframes tooltipIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/_tutorial.scss b/VirtualGloomhavenBoard/assets/scss/_tutorial.scss deleted file mode 100644 index 2329b6cb..00000000 --- a/VirtualGloomhavenBoard/assets/scss/_tutorial.scss +++ /dev/null @@ -1,33 +0,0 @@ -.tutorial { - font-family: Arial, Helvetica, sans-serif; - position: absolute; - max-width: 36rem; - background: radial-gradient(circle, rgba(241, 236, 232, 0.5) 31%, rgba(156, 124, 108, 0.3) 85%, rgba(81, 64, 30, 0.1) 100%), url("/img/bg.jpg"); - z-index: 2; - padding: 1rem; - border: 3px solid #452e27; - box-shadow: 0 -5px 40px 0 black; - text-shadow: initial; - color: black; - font-size: 1rem; - transition: all 1s; - - &.step-0 { - top: 25%; - left: 25%; - } - - &.step-1 { - right: 1rem; - top: 3.5rem; - } - - &.step-2 { - left: 0.5rem; - } - - .footer { - margin-top: 1rem; - justify-content: end; - } -} \ No newline at end of file diff --git a/VirtualGloomhavenBoard/assets/scss/main.scss b/VirtualGloomhavenBoard/assets/scss/main.scss deleted file mode 100644 index 38707dbf..00000000 --- a/VirtualGloomhavenBoard/assets/scss/main.scss +++ /dev/null @@ -1,11 +0,0 @@ -@use 'layout'; -@use 'form'; -@use 'modal'; -@use 'context-menu'; -@use 'tooltip'; -@use 'tutorial'; -@use 'board'; -@use 'creator'; -@use 'icons'; -@use 'screens'; - From a3406574ba867082a069110dd2545c1ca7f0e153 Mon Sep 17 00:00:00 2001 From: David North Date: Mon, 19 Jun 2023 22:15:08 +0100 Subject: [PATCH 50/60] Context menus now work in the same way as the original --- VirtualGloomhavenBoard/Indigo/build.sc | 4 + .../vgb-common/src/vgb/common/CommonMsg.scala | 11 +- .../src/vgb/common/ContextMenu.scala | 45 ------- .../vgb-common/src/vgb/common/Menu.scala | 97 +++++++++++++++ .../components/ContextMenuComponent.scala | 5 +- .../src/vgb/game/scenes/CreatorScene.scala | 2 + .../Indigo/vgb-ui/src/vgb/ui/Main.scala | 115 +++++++++++++++--- .../vgb-ui/src/vgb/ui/models/UiModel.scala | 9 +- .../components/ContextMenuComponent.scala | 78 ++++-------- .../models/components/MainMenuComponent.scala | 34 ++++++ .../ui/models/components/MenuComponent.scala | 113 +++++++++++++++++ .../src/vgb/ui/scenes/CreatorScene.scala | 31 ++++- .../src/vgb/ui/scenes/TyrianScene.scala | 2 +- .../Indigo/wwwroot/index.html | 3 + .../Indigo/wwwroot/js/app.js | 2 +- 15 files changed, 419 insertions(+), 132 deletions(-) delete mode 100644 VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/ContextMenu.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MainMenuComponent.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala diff --git a/VirtualGloomhavenBoard/Indigo/build.sc b/VirtualGloomhavenBoard/Indigo/build.sc index cc5c01d9..24cdafef 100644 --- a/VirtualGloomhavenBoard/Indigo/build.sc +++ b/VirtualGloomhavenBoard/Indigo/build.sc @@ -68,6 +68,10 @@ trait VgbModule extends ScalaJSModule { ivy"org.scala-js:scalajs-java-securerandom_sjs1_2.13:1.0.0" ) + override def esFeatures: T[ESFeatures] = T { + ESFeatures.Defaults.withESVersion(ESVersion.ES2015) + } + override def moduleKind = T(mill.scalajslib.api.ModuleKind.CommonJSModule) object test extends ScalaJSTests with TestModule.Munit { diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala index da8217fb..b33fbee8 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala @@ -5,13 +5,11 @@ import indigo.Point /** A message from the VGB app */ trait GloomhavenMsg -object GloomhavenMsg: - given CanEqual[GloomhavenMsg, GloomhavenMsg] = CanEqual.derived - /** General messages that can be used across many scenes - */ +/** General messages that can be used across many scenes + */ enum GeneralMsgType extends GloomhavenMsg: - case ShowContextMenu(position: Point, menu: ContextMenu) + case ShowContextMenu(position: Point, menu: Menu) case CloseContextMenu enum CreatorMsgType extends GloomhavenMsg: @@ -21,3 +19,6 @@ enum CreatorMsgType extends GloomhavenMsg: case RemoveOverlay(id: Int, o: BoardOverlayType) case RotateRoom(r: RoomType) case RemoveRoom(r: RoomType) + case CreateNewScenario + case ShowImportDialog + case ShowExportDialog diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/ContextMenu.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/ContextMenu.scala deleted file mode 100644 index 05cfd1c0..00000000 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/ContextMenu.scala +++ /dev/null @@ -1,45 +0,0 @@ -package vgb.common - -import indigo.Batch - -final case class ContextMenu(items: Batch[MenuItem | MenuSeparator]) { - def add(item: Option[MenuItem | MenuSeparator]): ContextMenu = - item match { - case Some(i) => this.add(i) - case None => this - } - - def add(item: MenuItem | MenuSeparator): ContextMenu = - this.copy(items = items :+ item) - - def addOptions(items: Batch[Option[MenuItem | MenuSeparator]]): ContextMenu = - this.copy(items = this.items ++ Batch.fromArray(items.toArray.flatten)) - - def add(items: Batch[MenuItem | MenuSeparator]): ContextMenu = - this.copy(items = this.items ++ items) - -} - -final case class MenuItem( - name: String, - selected: Boolean, - cmd: Option[GloomhavenMsg], - subItems: Batch[MenuItem | MenuSeparator] -) { - val hasSubMenu = !subItems.isEmpty - - def withSelected(s: Boolean) = - this.copy(selected = s) -} - -final case class MenuSeparator() - -object ContextMenu: - def apply(): ContextMenu = - ContextMenu(Batch.empty) - -object MenuItem: - def apply(name: String, cmd: GloomhavenMsg): MenuItem = - MenuItem(name, false, Some(cmd), Batch.empty) - def apply(name: String, subItems: Batch[MenuItem | MenuSeparator]): MenuItem = - MenuItem(name, false, None, subItems) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala new file mode 100644 index 00000000..c5d73bf0 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala @@ -0,0 +1,97 @@ +package vgb.common + +import indigo.Batch + +final case class Menu(private val internalItems: Batch[MenuItemTrait | MenuSeparator]) { + val items: Batch[MenuItemTrait | MenuSeparator] = assignIds(internalItems, -1)._1; + + def updateItems(items: Batch[MenuItemTrait | MenuSeparator]) = + this.copy(internalItems = items) + + def add(item: Option[MenuItemTrait | MenuSeparator]): Menu = + item match { + case Some(i) => this.add(i) + case None => this + } + + def add(item: MenuItemTrait | MenuSeparator): Menu = + this.copy(internalItems = internalItems :+ item) + + def addOptions(items: Batch[Option[MenuItemTrait | MenuSeparator]]): Menu = + this.copy(internalItems = internalItems ++ Batch.fromArray(items.toArray.flatten)) + + def add(items: Batch[MenuItemTrait | MenuSeparator]): Menu = + this.copy(internalItems = internalItems ++ items) + + private def assignIds( + items: Batch[MenuItemTrait | MenuSeparator], + initialId: Byte + ): (Batch[MenuItemTrait | MenuSeparator], Byte) = + items + .foldLeft((Batch.empty[MenuItemTrait | MenuSeparator], initialId))((t, i) => + t match { + case (seenItems, lastId) => + i match { + case i: (MenuItem | MenuLink) => + val (newItem, newId) = assignIdToItem(i, lastId) + (seenItems :+ newItem, (newId + 1).toByte) + case _ => (seenItems :+ i, lastId) + } + } + ) + + private def assignIdToItem(item: MenuItem | MenuLink, lastId: Byte): (MenuItem | MenuLink, Byte) = + val (subMenus, newId) = assignIds(item.subItems, lastId) + val nextId = (newId + 1).toByte; + + item match { + case i: MenuItem => + (i.copy(subItems = subMenus, id = nextId), nextId) + case i: MenuLink => + (i.copy(subItems = subMenus, id = nextId), nextId) + }; +} + +trait MenuItemTrait: + val id: Byte + val name: String + val subItems: Batch[MenuItemTrait | MenuSeparator] + val hasSubMenu = !subItems.isEmpty + +final case class MenuItem( + id: Byte, + name: String, + selected: Boolean, + open: Boolean, + cmd: Option[GloomhavenMsg], + subItems: Batch[MenuItemTrait | MenuSeparator] +) extends MenuItemTrait { + def withSelected(s: Boolean) = + this.copy(selected = s) +} + +final case class MenuSeparator() + +final case class MenuLink( + id: Byte, + name: String, + url: String, + target: String, + subItems: Batch[MenuItemTrait | MenuSeparator] +) extends MenuItemTrait + +object Menu: + def apply(): Menu = + Menu(Batch.empty) + +object MenuItem: + def apply(name: String, cmd: GloomhavenMsg): MenuItem = + MenuItem(0, name, false, false, Some(cmd), Batch.empty) + def apply(name: String, subItems: Batch[MenuItemTrait | MenuSeparator]): MenuItem = + MenuItem(0, name, false, false, None, subItems) + +object MenuLink: + def apply(name: String, url: String, target: String): MenuLink = + MenuLink(0, name, url, target, Batch.empty) + def apply(name: String, url: String): MenuLink = + MenuLink(0, name, url, "_self", Batch.empty) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala index 16706924..cc4faebe 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala @@ -4,14 +4,15 @@ import indigo.* import vgb.common.* import vgb.game.models.ScenarioMonster import vgb.game.models.BoardOverlay +import vgb.common.{MenuSeparator, MenuItem} object ContextMenuComponent: def getForCreator( room: Option[RoomType], monster: Option[ScenarioMonster], overlays: Batch[BoardOverlay] - ): ContextMenu = - ContextMenu() + ): Menu = + Menu() .add( monster .map(m => diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala index a3acaf16..4ab2b24e 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -313,4 +313,6 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg Outcome(model.copy(rooms = model.rooms.map(r1 => if r1 == room then newRoom else r1))) case None => Outcome(model) } + + case _ => Outcome(model) } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala index b694804f..80bc541f 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala @@ -4,22 +4,29 @@ import cats.effect.IO import tyrian.* import tyrian.Html.* import org.scalajs.dom.document +import org.scalajs.dom.window import vgb.game.{Main => VgbGame} import vgb.common.* import scala.scalajs.js.annotation.* import scala.concurrent.duration.DurationDouble import vgb.ui.models.components.ContextMenuComponent +import vgb.ui.models.components.MainMenuComponent import indigo.shared.collections.Batch +import indigo.shared.datatypes.Point +import vgb.common.{MenuItem, MenuSeparator} +import vgb.ui.models.UiModel enum Msg: case NoOp case RetryIndigo - case IndigoReceive(msg: GloomhavenMsg) extends Msg - case IndigoSend(msg: GloomhavenMsg) extends Msg - case StartIndigo extends Msg - case OpenContextItem(item: MenuItem) extends Msg - case CloseContextMenu extends Msg + case IndigoReceive(msg: GloomhavenMsg) + case IndigoSend(msg: GloomhavenMsg) + case StartIndigo + case OpenContextItem(itemId: Byte) + case CloseContextItem(itemId: Byte) + case CloseContextMenu + case ToggleMainMenu @JSExportTopLevel("TyrianApp") object Main extends TyrianApp[Msg, Model]: @@ -52,16 +59,27 @@ object Main extends TyrianApp[Msg, Model]: (model, Cmd.Run(task)) case Msg.RetryIndigo => - (model, Cmd.emitAfterDelay(Msg.StartIndigo, 0.25.seconds)) + (model, Cmd.emitAfterDelay(Msg.StartIndigo, 0.1.seconds)) case Msg.CloseContextMenu => ( model.copy(sceneModel = model.sceneModel.updateContextMenu(None)), Cmd.None ) - case Msg.OpenContextItem(item) => + case Msg.OpenContextItem(i) => model.sceneModel.contextMenu match { case Some((p, menu)) => - val newMenu = (p, menu.copy(items = updateContextMenuItem(menu.items, item))) + val newMenu = (p, menu.updateItems(updateContextMenuItem(menu.items, i, true))) + ( + model.copy(sceneModel = model.sceneModel.updateContextMenu(Some(newMenu))), + Cmd.None + ) + case None => (model, Cmd.None) + } + + case Msg.CloseContextItem(i) => + model.sceneModel.contextMenu match { + case Some((p, menu)) => + val newMenu = (p, menu.updateItems(updateContextMenuItem(menu.items, i, false))) ( model.copy(sceneModel = model.sceneModel.updateContextMenu(Some(newMenu))), Cmd.None @@ -69,16 +87,26 @@ object Main extends TyrianApp[Msg, Model]: case None => (model, Cmd.None) } case Msg.NoOp => (model, Cmd.None) + case Msg.ToggleMainMenu => + ( + model.copy(sceneModel = model.sceneModel.toggleMainMenu()), + Cmd.None + ) def view(model: Model): Html[Msg] = + val sceneModel = model.scene.getModel(model) + div(id := "content", `class` := "content")( div(`class` := "header")( - model.scene - .header(model.scene.getModel(model)) - .map(Msg.IndigoSend(_)) + List( + MainMenuComponent.render(sceneModel.mainMenu, sceneModel.showMainMenu) + ) ++ + model.scene + .getHeader(sceneModel) + .map(e => e.map(Msg.IndigoSend(_))) ), div(`class` := "main", attribute("aria-label", "Gloomhaven board layout"))( - model.sceneModel.contextMenu match { + sceneModel.contextMenu match { case Some(m) => m match { case (pos, menu) => @@ -139,8 +167,26 @@ object Main extends TyrianApp[Msg, Model]: case (msg: GeneralMsgType, _) => msg match { case GeneralMsgType.ShowContextMenu(p, m) => - val newMenu = if m.items.isEmpty then None else Some(p, m) - (model.copy(sceneModel = model.sceneModel.updateContextMenu(newMenu)), Cmd.None) + val newMenu = + if m.items.isEmpty then None + else + val newMenu = Menu() + .add( + m.items.map(i => + i match { + case i: MenuItem => assignCancelButtons(i) + case _ => i + } + ) + ) + .add(MenuSeparator()) + .add(MenuItem("Cancel", Batch.empty)) + + Some(getContextPosition(p), newMenu) + ( + model.copy(sceneModel = model.sceneModel.updateContextMenu(newMenu)), + Cmd.None + ) case GeneralMsgType.CloseContextMenu => (model.copy(sceneModel = model.sceneModel.updateContextMenu(None)), Cmd.None) } @@ -150,14 +196,18 @@ object Main extends TyrianApp[Msg, Model]: } def updateContextMenuItem( - items: Batch[MenuItem | MenuSeparator], - selectedItem: MenuItem - ): Batch[MenuItem | MenuSeparator] = + items: Batch[MenuItemTrait | MenuSeparator], + idToFind: Byte, + opened: Boolean + ): Batch[MenuItemTrait | MenuSeparator] = items .map(item => item match { case i: MenuItem => - i.copy(selected = i == selectedItem, subItems = updateContextMenuItem(i.subItems, selectedItem)) + i.copy( + open = (i.id == idToFind) && opened, + subItems = updateContextMenuItem(i.subItems, idToFind, opened) + ) case _ => item } ) @@ -165,3 +215,32 @@ object Main extends TyrianApp[Msg, Model]: @SuppressWarnings(Array("scalafix:DisableSyntax.null")) private def gameDivExists(id: String): Boolean = document.getElementById(id) != null + + private def getContextPosition(p: Point) = + document.getElementById(gameDivId) match { + case null => p + case gameWrapper => + val padding = 22 + Point( + (p.x + padding - gameWrapper.scrollLeft).toInt, + (p.y + padding - gameWrapper.scrollTop).toInt + ) + } + + private def assignCancelButtons(item: MenuItem): MenuItem = + if item.hasSubMenu then + val subItems = item.subItems + .map(item => + item match { + case i: MenuItem => assignCancelButtons(i) + case _ => item + } + ) + + item + .copy(subItems = + subItems :+ + MenuSeparator() :+ + MenuItem("Cancel", Batch.empty) + ) + else item diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/UiModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/UiModel.scala index 0c3f87a8..0bf074e2 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/UiModel.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/UiModel.scala @@ -1,8 +1,11 @@ package vgb.ui.models import indigo.shared.datatypes.Point -import vgb.common.ContextMenu +import vgb.common.Menu trait UiModel: - val contextMenu: Option[(Point, ContextMenu)] - def updateContextMenu(menu: Option[(Point, ContextMenu)]): UiModel + val contextMenu: Option[(Point, Menu)] + val mainMenu: Menu + val showMainMenu: Boolean + def updateContextMenu(menu: Option[(Point, Menu)]): UiModel + def toggleMainMenu(): UiModel diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala index e1f8d786..9812afd2 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala @@ -2,72 +2,48 @@ package vgb.ui.models.components import indigo.shared.datatypes.Point import indigo.shared.collections.Batch -import vgb.common.ContextMenu -import tyrian.* -import tyrian.Html.* +import indigo.* +import vgb.common.Menu import vgb.common.MenuItem import vgb.common.MenuSeparator +import tyrian.* +import tyrian.Html.* import vgb.ui.Msg -import indigo.shared.IndigoLogger object ContextMenuComponent: - def render(pos: Point, menu: ContextMenu): Html[Msg] = + def render(pos: Point, menu: Menu): Html[Msg] = val hasItems = menu.items.exists(i => i match { case _: MenuItem => true case _ => false } ) - IndigoLogger.consoleLog(menu.items.toString()) + + val isSubMenuOpen = menu.items.exists(i => + i match { + case i: MenuItem => + i.open || i.subItems.exists(_ match { + case i: MenuItem => i.open + case _ => false + }) + case _ => false + } + ) + div( attributes( - ("class", s"""context-menu ${if hasItems then "open" else "closed"}"""), + ("id", "context-menu"), + ( + "class", + s"""context-menu ${if hasItems then "open" else "closed"} ${if isSubMenuOpen then "sub-menu-open" else ""}""" + .trim() + ), ("aria-live", "polite"), ("aria-atomic", "true"), - ("aria-hidden", if hasItems then "false" else "true") + ("aria-hidden", if hasItems then "false" else "true"), + ("style", s"""top: ${pos.y}px; left: ${pos.x}px""") ) )( - nav( - ul( - renderItems(menu.items) - ) - ) + if hasItems then MenuComponent.render(menu, hasItems) + else Empty ) - - private def renderItem(item: MenuItem, separator: Boolean): Html[Msg] = - val menuList = - if item.hasSubMenu then - List( - text(item.name), - div( - ul( - renderItems(item.subItems) - ) - ) - ) - else List(text(item.name)) - - li( - `class` := s"""${if item.hasSubMenu then "has-sub-menu" else ""} ${if separator then " separator" else ""}""", - onClick( - item.cmd match { - case Some(c) => Msg.IndigoSend(c) - case None => Msg.OpenContextItem(item) - } - ) - )(menuList) - - private def renderItems(items: Batch[MenuItem | MenuSeparator]): List[Html[Msg]] = - items - .foldRight(Batch.empty[Html[Msg]], false)((item, h) => - h match { - case (html, separator) => - item match { - case i: MenuItem => (html :+ renderItem(i, separator), false) - case s: MenuSeparator => (html, true) - } - } - ) - ._1 - .reverse - .toList diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MainMenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MainMenuComponent.scala new file mode 100644 index 00000000..92d43613 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MainMenuComponent.scala @@ -0,0 +1,34 @@ +package vgb.ui.models.components + +import vgb.common.Menu +import vgb.common.MenuLink +import vgb.common.MenuSeparator +import vgb.ui.Msg +import tyrian.* +import tyrian.Html.* + +object MainMenuComponent: + def render(menu: Menu, visible: Boolean) = + div( + attributes( + ("class", s"""menu ${if visible then "show" else "hide"}"""), + ("aria-label", "Toggle Menu"), + ("aria-keyshortcuts", "m"), + ("role", "button"), + ("aria-pressed", if visible then "true" else "false") + ) ++ + List(onClick(Msg.ToggleMainMenu)) + )( + MenuComponent.render( + menu + .add(MenuSeparator()) + .add( + MenuLink( + "Donate", + "https://github.com/sponsors/PurpleKingdomGames?o=esb", + "_new" + ) + ), + visible + ) + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala new file mode 100644 index 00000000..10c276c2 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala @@ -0,0 +1,113 @@ +package vgb.ui.models.components + +import tyrian.* +import tyrian.Html.* +import vgb.ui.Msg +import vgb.common.Menu +import vgb.common.MenuItem +import vgb.common.MenuLink +import vgb.common.MenuSeparator +import indigo.shared.collections.Batch +import vgb.common.MenuItemTrait + +object MenuComponent: + def render(menu: Menu, visible: Boolean): Html[Msg] = + nav(attribute("aria-hidden", if visible then "false" else "true"))( + ul(attribute("role", "menu"))( + renderItems(None, menu.items) + ) + ) + + private def renderItem(parentItem: Option[MenuItem], item: MenuItemTrait, separator: Boolean): Html[Msg] = + val menuItemElem = item match { + case i: MenuItem => text(i.name) + case l: MenuLink => a(href := l.url, target := l.target)(l.name) + } + + val isOpen = item match { + case i: MenuItem => + i.open || i.subItems.exists(_ match { + case i: MenuItem => i.open + case _ => false + }) + case _ => false + } + + val menuList = + if item.hasSubMenu then + List( + menuItemElem, + div( + ul(`class` := s"""${if isOpen then "open" else ""}""")( + renderItems( + item match { + case i: MenuItem => Some(i) + case _ => None + }, + item.subItems + ) + ) + ) + ) + else List(menuItemElem) + + val selected = item match { + case i: MenuItem => i.selected + case _ => false + } + + val isCancel = + item match { + case item: MenuItem => + item.cmd match { + case Some(_) => false + case None => + parentItem match { + case Some(_) => true + case None => item.subItems.isEmpty + } + } + case _ => false + } + + li( + attributes( + ( + "class", + s"""${if item.hasSubMenu then "has-sub-menu" else ""}${if selected then " selected" else ""}${ + if separator then " separator" else "" + }${if isCancel then " cancel cancel-menu" else ""}""".trim() + ), + ("tabIndex", "0"), + ("role", "menuitem") + ) ++ + (item match { + case item: MenuItem => + List(onClick(item.cmd match { + case Some(c) => Msg.IndigoSend(c) + case None => + parentItem match { + case Some(p) => Msg.CloseContextItem(p.id) + case None => + if item.subItems.isEmpty then Msg.CloseContextMenu + else Msg.OpenContextItem(item.id) + } + })) + case _ => List.empty + }) + )(menuList) + + private def renderItems(parentItem: Option[MenuItem], items: Batch[MenuItemTrait | MenuSeparator]): List[Html[Msg]] = + items + .foldRight(Batch.empty[Html[Msg]], false)((item, h) => + h match { + case (html, separator) => + item match { + case i: MenuItemTrait => (html :+ renderItem(parentItem, i, separator), false) + case s: MenuSeparator => (html, true) + } + } + ) + ._1 + .reverse + .toList diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala index 1fd84881..53696950 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -4,10 +4,13 @@ import cats.effect.IO import indigo.shared.datatypes.Point import tyrian.* import tyrian.Html.* +import vgb.common.CreatorMsgType import vgb.common.GloomhavenMsg -import vgb.common.ContextMenu +import vgb.common.Menu import vgb.ui.Model import vgb.ui.models.UiModel +import vgb.common.MenuItem +import vgb.common.MenuSeparator object CreatorScene extends TyrianScene { type SceneModel = CreatorModel @@ -24,16 +27,32 @@ object CreatorScene extends TyrianScene { (model, Cmd.None) } - def header(model: CreatorModel): Html[GloomhavenMsg] = - div() + def getHeader(model: CreatorModel): List[Html[GloomhavenMsg]] = List( + header( + attribute("aria-label", "Scenario Title") + )(span(`class` := "title")(input(`type` := "text", placeholder := "Enter Scenario Title", maxLength := 30))) + ) } final case class CreatorModel( - contextMenu: Option[(Point, ContextMenu)] + mainMenu: Menu, + showMainMenu: Boolean, + contextMenu: Option[(Point, Menu)] ) extends UiModel { - def updateContextMenu(menu: Option[(Point, ContextMenu)]): UiModel = + def updateContextMenu(menu: Option[(Point, Menu)]): UiModel = this.copy(contextMenu = menu) + def toggleMainMenu(): UiModel = + this.copy(showMainMenu = showMainMenu != true) } object CreatorModel: - def apply(): CreatorModel = CreatorModel(None) + def apply(): CreatorModel = CreatorModel( + Menu() + .add(Some(MenuItem("Create New", CreatorMsgType.CreateNewScenario))) + .add(MenuSeparator()) + .add(Some(MenuItem("Export", CreatorMsgType.ShowExportDialog))) + .add(Some(MenuItem("Import", CreatorMsgType.ShowImportDialog))) + .add(MenuSeparator()), + false, + None + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala index b1b252c1..462aa179 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala @@ -12,4 +12,4 @@ trait TyrianScene: def getModel(model: Model): SceneModel def update(msg: GloomhavenMsg, model: SceneModel): (SceneModel, Cmd[IO, GloomhavenMsg]) - def header(model: SceneModel): Html[GloomhavenMsg] + def getHeader(model: SceneModel): List[Html[GloomhavenMsg]] diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/index.html b/VirtualGloomhavenBoard/Indigo/wwwroot/index.html index 011fd383..081621d9 100644 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/index.html +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/index.html @@ -30,6 +30,9 @@ + + + diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js b/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js index ddc7ebe8..957f3792 100644 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js @@ -1,5 +1,5 @@ //require('@microsoft/signalr') -import * as t from '../../out/vgb-ui/fastLinkJs.dest/main.js'; +import * as t from '../../out/vgb-ui/fastLinkJS.dest/main.js'; t.TyrianApp.launch("main") /* const conn = new signalR From d65bc14e6a019a1dc0b62d9c39a414009cd1e929 Mon Sep 17 00:00:00 2001 From: David North Date: Tue, 20 Jun 2023 08:31:13 +0100 Subject: [PATCH 51/60] Adds Scenario Title and fixes context menu showing with no items in it --- .../vgb-common/src/vgb/common/CommonMsg.scala | 1 + .../vgb-common/src/vgb/common/Menu.scala | 5 ++++- .../Indigo/vgb-ui/src/vgb/ui/Main.scala | 17 ++++++++++++----- .../components/ContextMenuComponent.scala | 8 +------- .../src/vgb/ui/scenes/CreatorScene.scala | 19 +++++++++++++++++-- .../src/vgb/ui/scenes/TyrianScene.scala | 3 ++- 6 files changed, 37 insertions(+), 16 deletions(-) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala index b33fbee8..37c7546c 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala @@ -22,3 +22,4 @@ enum CreatorMsgType extends GloomhavenMsg: case CreateNewScenario case ShowImportDialog case ShowExportDialog + case ChangeScenarioTitle(title: String) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala index c5d73bf0..433b3717 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala @@ -4,7 +4,10 @@ import indigo.Batch final case class Menu(private val internalItems: Batch[MenuItemTrait | MenuSeparator]) { val items: Batch[MenuItemTrait | MenuSeparator] = assignIds(internalItems, -1)._1; - + val isEmpty: Boolean = items.isEmpty || items.exists(_ match { + case _: MenuItemTrait => true + case _ => false + }) == false def updateItems(items: Batch[MenuItemTrait | MenuSeparator]) = this.copy(internalItems = items) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala index 80bc541f..43ca86db 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala @@ -16,6 +16,8 @@ import indigo.shared.collections.Batch import indigo.shared.datatypes.Point import vgb.common.{MenuItem, MenuSeparator} import vgb.ui.models.UiModel +import vgb.ui.scenes.CreatorModel +import tyrian.cmds.Logger enum Msg: case NoOp @@ -96,14 +98,19 @@ object Main extends TyrianApp[Msg, Model]: def view(model: Model): Html[Msg] = val sceneModel = model.scene.getModel(model) - div(id := "content", `class` := "content")( + div( + id := "content", + `class` := s"""content ${sceneModel match { + case _: CreatorModel => "scenario-creator" + case _ => "" + }}""" + )( div(`class` := "header")( List( MainMenuComponent.render(sceneModel.mainMenu, sceneModel.showMainMenu) ) ++ model.scene .getHeader(sceneModel) - .map(e => e.map(Msg.IndigoSend(_))) ), div(`class` := "main", attribute("aria-label", "Gloomhaven board layout"))( sceneModel.contextMenu match { @@ -167,8 +174,8 @@ object Main extends TyrianApp[Msg, Model]: case (msg: GeneralMsgType, _) => msg match { case GeneralMsgType.ShowContextMenu(p, m) => - val newMenu = - if m.items.isEmpty then None + val someMenu = + if m.isEmpty then None else val newMenu = Menu() .add( @@ -184,7 +191,7 @@ object Main extends TyrianApp[Msg, Model]: Some(getContextPosition(p), newMenu) ( - model.copy(sceneModel = model.sceneModel.updateContextMenu(newMenu)), + model.copy(sceneModel = model.sceneModel.updateContextMenu(someMenu)), Cmd.None ) case GeneralMsgType.CloseContextMenu => diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala index 9812afd2..6a8e26b3 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala @@ -12,13 +12,7 @@ import vgb.ui.Msg object ContextMenuComponent: def render(pos: Point, menu: Menu): Html[Msg] = - val hasItems = menu.items.exists(i => - i match { - case _: MenuItem => true - case _ => false - } - ) - + val hasItems = menu.isEmpty == false val isSubMenuOpen = menu.items.exists(i => i match { case i: MenuItem => diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala index 53696950..2f447bdb 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -11,6 +11,7 @@ import vgb.ui.Model import vgb.ui.models.UiModel import vgb.common.MenuItem import vgb.common.MenuSeparator +import vgb.ui.Msg object CreatorScene extends TyrianScene { type SceneModel = CreatorModel @@ -23,18 +24,31 @@ object CreatorScene extends TyrianScene { def update(msg: vgb.common.GloomhavenMsg, model: CreatorModel): (CreatorModel, Cmd[IO, GloomhavenMsg]) = msg match { + case CreatorMsgType.ChangeScenarioTitle(t) => (model.copy(scenarioTitle = t), Cmd.None) case _ => (model, Cmd.None) } - def getHeader(model: CreatorModel): List[Html[GloomhavenMsg]] = List( + def getHeader(model: CreatorModel): List[Html[Msg]] = List( header( attribute("aria-label", "Scenario Title") - )(span(`class` := "title")(input(`type` := "text", placeholder := "Enter Scenario Title", maxLength := 30))) + )( + span(`class` := "title")( + input( + `type` := "text", + placeholder := "Enter Scenario Title", + maxLength := 30, + onInput(_ match { + case t => Msg.IndigoReceive(CreatorMsgType.ChangeScenarioTitle(t)) + }) + ) + ) + ) ) } final case class CreatorModel( + scenarioTitle: String, mainMenu: Menu, showMainMenu: Boolean, contextMenu: Option[(Point, Menu)] @@ -47,6 +61,7 @@ final case class CreatorModel( object CreatorModel: def apply(): CreatorModel = CreatorModel( + "", Menu() .add(Some(MenuItem("Create New", CreatorMsgType.CreateNewScenario))) .add(MenuSeparator()) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala index 462aa179..c4b5a37c 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala @@ -6,10 +6,11 @@ import tyrian.Html import vgb.common.GloomhavenMsg import vgb.ui.Model import vgb.ui.models.UiModel +import vgb.ui.Msg trait TyrianScene: type SceneModel <: UiModel def getModel(model: Model): SceneModel def update(msg: GloomhavenMsg, model: SceneModel): (SceneModel, Cmd[IO, GloomhavenMsg]) - def getHeader(model: SceneModel): List[Html[GloomhavenMsg]] + def getHeader(model: SceneModel): List[Html[Msg]] From 010bd1599effe1ac5d216f64d27151708fdcd90f Mon Sep 17 00:00:00 2001 From: David North Date: Thu, 22 Jun 2023 07:43:47 +0100 Subject: [PATCH 52/60] Starts to add left menu to creator and fixes footer --- .../Indigo/vgb-ui/src/vgb/ui/Main.scala | 62 +++++++-------- .../src/vgb/ui/scenes/CreatorScene.scala | 5 ++ .../src/vgb/ui/scenes/TyrianScene.scala | 1 + .../Indigo/wwwroot/scss/_layout.scss | 77 +++++++++---------- .../Indigo/wwwroot/scss/_screens.scss | 18 ++++- 5 files changed, 93 insertions(+), 70 deletions(-) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala index 43ca86db..8e1a371e 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala @@ -113,17 +113,23 @@ object Main extends TyrianApp[Msg, Model]: .getHeader(sceneModel) ), div(`class` := "main", attribute("aria-label", "Gloomhaven board layout"))( - sceneModel.contextMenu match { - case Some(m) => - m match { - case (pos, menu) => - List( - div(id := gameDivId, `class` := "board-wrapper")(), - ContextMenuComponent.render(pos, menu) - ) + List(div(`class` := "map-bg")()) ++ + model.scene + .getBoardAdditions(sceneModel) + ++ + ( + sceneModel.contextMenu match { + case Some(m) => + m match { + case (pos, menu) => + List( + div(id := gameDivId, `class` := "board-wrapper")(), + ContextMenuComponent.render(pos, menu) + ) + } + case None => List(div(id := gameDivId, `class` := "board-wrapper")()) } - case None => List(div(id := gameDivId, `class` := "board-wrapper")()) - } + ) ), footer( div(`class` := "credits")( @@ -137,27 +143,23 @@ object Main extends TyrianApp[Msg, Model]: ) ), div(`class` := "pkg")( - div(`class` := "copy-wrapper")( - span(`class` := "pkgCopy")( - text("Developed by"), - a(href := "https://purplekingdomgames.com/")("Purple Kingdom Games") - ), - div(`class` := "sponsor")( - iframe( - `class` := "sponsor-button", - src := "https://github.com/sponsors/PurpleKingdomGames/button", - title := "Sponsor Purple Kingdom Games", - attribute("aria-hidden", "true") - )() - ) + span(`class` := "pkgCopy")( + text("Developed by"), + a(href := "https://purplekingdomgames.com/")("Purple Kingdom Games") ), - div(`class` := "version")( - a( - target := "_new", - href := "https://github.com/PurpleKingdomGames/virtual-gloomhaven-board/issues/new/choose" - )("Report a bug"), - span(s"""Version ${appVersion}""") - ) + div(`class` := "sponsor")( + iframe( + `class` := "sponsor-button", + src := "https://github.com/sponsors/PurpleKingdomGames/button", + title := "Sponsor Purple Kingdom Games", + attribute("aria-hidden", "true") + )() + ), + a( + target := "_new", + href := "https://github.com/PurpleKingdomGames/virtual-gloomhaven-board/issues/new/choose" + )("Report a bug"), + span(s"""Version ${appVersion}""") ) ) ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala index 2f447bdb..dbd61e0f 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -45,6 +45,11 @@ object CreatorScene extends TyrianScene { ) ) ) + + def getBoardAdditions(model: CreatorModel): List[Html[Msg]] = List( + div(`class` := "page-shadow")(), + div(`class` := "action-list")() + ) } final case class CreatorModel( diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala index c4b5a37c..620e617b 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala @@ -13,4 +13,5 @@ trait TyrianScene: def getModel(model: Model): SceneModel def update(msg: GloomhavenMsg, model: SceneModel): (SceneModel, Cmd[IO, GloomhavenMsg]) + def getBoardAdditions(model: SceneModel): List[Html[Msg]] def getHeader(model: SceneModel): List[Html[Msg]] diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss index 8da58a90..87083144 100644 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss @@ -250,6 +250,17 @@ html { margin-bottom: 4.01rem; transition: margin-top 0.2s, margin-bottom 0.2s; + .map-bg { + position: absolute; + top: 0; + right: 0; + background-image: url('../static/img/compass.webp'); + width: 175px; + height: 254px; + opacity: 0.55; + z-index: 1; + } + .action-list { flex-grow: 1; flex-shrink: 0; @@ -451,14 +462,9 @@ html { position: relative; padding: 40px; - .map-bg { - position: absolute; - top: 0; - right: -175px; - background-image: url('../static/img/compass.webp'); - width: 175px; - height: 254px; - opacity: 0.55; + canvas { + position: relative; + z-index: 1; } } @@ -553,45 +559,38 @@ html { } .pkg { - padding: 1rem; - display: flex; - ; - flex-wrap: wrap; - justify-content: end; + padding: 0.7rem 1rem 1rem 1rem; + display: grid; + grid-template-columns: 1fr 1fr; + grid-gap: 0.3rem; - .copy-wrapper { - width: 100%; - display: flex; - text-align: right; - align-items: center; - position: relative; - justify-content: flex-end; - margin-bottom: 0.3rem; - - .sponsor { - position: relative; - - .sponsor-button { - height: 35px; - width: 128px; - display: block; - border: none; - transform: scale(.65); - } + .pkgCopy { + line-height: 1.4rem; + + a { + padding-left: 0.5rem; } } - .version { - width: 100%; - padding-right: 1.7rem; + .sponsor { + justify-self: end; position: relative; - top: -0.4rem; - text-align: right; - a { - margin-right: 10.3rem; + .sponsor-button { + height: 35px; + width: 128px; + display: block; + border: none; + position: absolute; + right: -23px; + transform: scale(.65); + top: -0.4rem; } } + + span { + justify-self: end; + } } } diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss index 9293874f..4ae348f3 100644 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss @@ -204,7 +204,23 @@ // Medium devices (tablets, 768px and up) -@media (max-width: 991px) {} +@media (max-width: 991px) { + html { + .content { + footer { + font-size: 0.8rem; + + .pkg { + padding-top: 1rem; + + .pkgCopy { + line-height: 0.9rem; + } + } + } + } + } +} // 4k+ @media (min-width: 2800px) { From 6f67ecf81399c8a184d8dcbe095032c2969712ad Mon Sep 17 00:00:00 2001 From: David North Date: Thu, 29 Jun 2023 08:30:59 +0100 Subject: [PATCH 53/60] Can now drag items from left menu to the board --- .../vgb-common/src/vgb/common/CommonMsg.scala | 5 + .../src/vgb/common/DragDropItem.scala | 3 + .../src/vgb/common/DragDropSection.scala | 5 + .../Indigo/vgb-game/src/vgb/game/Events.scala | 6 +- .../Indigo/vgb-game/src/vgb/game/Main.scala | 1 + .../src/vgb/game/models/DragData.scala | 14 +- .../src/vgb/game/models/GameRules.scala | 6 +- .../components/BoardOverlayComponent.scala | 2 +- .../models/components/DragMenuComponent.scala | 42 ++++++ .../models/components/RoomComponent.scala | 2 +- .../models/sceneModels/CreatorModel.scala | 28 +--- .../models/sceneModels/CreatorViewModel.scala | 10 +- .../src/vgb/game/scenes/CreatorScene.scala | 138 ++++++++++-------- .../src/vgb/ui/scenes/CreatorScene.scala | 51 ++++++- .../Indigo/wwwroot/scss/_creator.scss | 2 + 15 files changed, 209 insertions(+), 106 deletions(-) create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/DragDropItem.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/DragDropSection.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala index 37c7546c..05951673 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala @@ -1,6 +1,7 @@ package vgb.common import indigo.Point +import indigo.shared.collections.Batch /** A message from the VGB app */ @@ -23,3 +24,7 @@ enum CreatorMsgType extends GloomhavenMsg: case ShowImportDialog case ShowExportDialog case ChangeScenarioTitle(title: String) + case UpdateDragMenu(sections: Batch[DragDropSection]) + case SetSelectedDragSection(sectionName: String) + case NewDragStart(dragItem: RoomType | BoardOverlayType | MonsterType) + case DragEnd diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/DragDropItem.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/DragDropItem.scala new file mode 100644 index 00000000..47b13fad --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/DragDropItem.scala @@ -0,0 +1,3 @@ +package vgb.common + +final case class DragDropItem(item: BoardOverlayType | MonsterType | RoomType, dragging: Boolean) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/DragDropSection.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/DragDropSection.scala new file mode 100644 index 00000000..a8fc2038 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/DragDropSection.scala @@ -0,0 +1,5 @@ +package vgb.common + +import indigo.shared.collections.Batch + +final case class DragDropSection(name: String, items: Batch[DragDropItem]) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Events.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Events.scala index 62a52826..d0deb43f 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Events.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Events.scala @@ -2,9 +2,9 @@ package vgb.game import indigo.shared.events.GlobalEvent import indigo.shared.datatypes.Point -import vgb.common.RoomType +import vgb.game.models.Room import vgb.game.models.ScenarioMonster import vgb.game.models.BoardOverlay -final case class MoveStart(originalPos: Point, drag: RoomType | ScenarioMonster | BoardOverlay) extends GlobalEvent -final case class MoveEnd(newPos: Point, drag: RoomType | ScenarioMonster | BoardOverlay) extends GlobalEvent +final case class MoveStart(originalPos: Point, drag: Room | ScenarioMonster | BoardOverlay) extends GlobalEvent +final case class MoveEnd(newPos: Point, drag: Room | ScenarioMonster | BoardOverlay) extends GlobalEvent diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala index e1450849..9ce52f4a 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala @@ -57,6 +57,7 @@ final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) AssetType.Font(AssetName("PirateOne"), AssetPath("fonts/PirataOne-Gloomhaven.woff2")) ) ) + .addGlobalEvents(SceneEvent.SceneChange(SceneName("creator-scene"), SceneName("creator-scene"), Seconds(0))) def setup( bootData: Size, diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/DragData.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/DragData.scala index bc014061..0b8cc032 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/DragData.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/DragData.scala @@ -1,7 +1,7 @@ package vgb.game.models import indigo.* -import vgb.common.RoomType +import vgb.game.models.Room import vgb.game.models.ScenarioMonster import vgb.game.models.BoardOverlay import vgb.common.Flag @@ -9,7 +9,7 @@ import vgb.common.Flag final case class DragData( val originalPos: Point, val pos: Point, - val dragger: RoomType | ScenarioMonster | BoardOverlay, + val dragger: Room | ScenarioMonster | BoardOverlay, val hasMoved: Boolean ) { def getCellMap( @@ -24,13 +24,9 @@ final case class DragData( case o: BoardOverlay => o.worldCells.map(c => (c, -o.overlayType.flag.value)) ++ o.copy(origin = pos).worldCells.map(c => (c, o.overlayType.flag.value)) - case r: RoomType => - rooms.find(r1 => r1.roomType == r) match { - case Some(r) => - r.worldCells.map(c => (c, -Flag.Room.value)) ++ - r.copy(origin = pos).worldCells.map(c => (c, Flag.Room.value)) - case None => Batch.empty - } + case r: Room => + r.worldCells.map(c => (c, -Flag.Room.value)) ++ + r.copy(origin = pos).worldCells.map(c => (c, Flag.Room.value)) } cells.foldLeft(map)((m, c) => diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala index 4dafefcc..3153008b 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala @@ -12,7 +12,8 @@ object GameRules: cellMap: Map[Point, Int] ): Batch[ScenarioMonster] = if (isValidMonsterPos(newPos, monster, cellMap)) - monsters.map(m => if m == monster then m.copy(initialPosition = newPos) else m) + monsters.filter(m => m != monster) + :+ monster.copy(initialPosition = newPos) else monsters @@ -23,7 +24,8 @@ object GameRules: cellMap: Map[Point, Int] ): Batch[BoardOverlay] = if (isValidOverlayPos(newPos, overlay, cellMap)) - overlays.map(o => if o.id == overlay.id then o.copy(origin = newPos) else o) + overlays.filter(o => o.id != overlay.id) + :+ overlay.copy(origin = newPos, id = if overlay.id == 0 then overlays.length + 1 else overlay.id) else overlays diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala index ff290dd3..c51a4b24 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala @@ -85,7 +85,7 @@ object BoardOverlayComponent: token .moveBy(Point(HexComponent.quarterSize.toInt, HexComponent.quarterSize.toInt)) else token - case _ => graphicGroup + case _ => graphicGroup.moveTo(origin) } ) }).withDepth(boardOverlay.overlayType match { diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala new file mode 100644 index 00000000..ffe5d891 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala @@ -0,0 +1,42 @@ +package vgb.game.models.components + +import vgb.game.models.sceneModels.CreatorModel +import vgb.common.DragDropSection +import vgb.common.DragDropItem +import vgb.common.RoomType +import vgb.common.Obstacle +import vgb.common.Treasure +import vgb.common.BaseGame +import vgb.common.MonsterType +import indigo.shared.collections.Batch + +object DragMenuComponent: + def getForModel(mode: CreatorModel) = + Batch( + DragDropSection( + "Tiles", + Batch( + DragDropItem(RoomType.RoomA1A, false) + ) + ), + DragDropSection("Doors", Batch.empty), + DragDropSection( + "Obstacles", + Batch( + DragDropItem(Obstacle.Boulder2, false) + ) + ), + DragDropSection( + "Misc.", + Batch( + DragDropItem(Treasure.Coin(BaseGame.Gloomhaven, 1), false) + ) + ), + DragDropSection( + "Monsters", + Batch( + DragDropItem(MonsterType.AestherAshblade, false) + ) + ), + DragDropSection("Bosses", Batch.empty) + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala index ebb95ea6..f21ce573 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala @@ -43,7 +43,7 @@ object RoomComponent: .withEventHandler((g, e) => e match { case MouseEvent.MouseDown(p, _) if g.bounds.contains(p + camera.position) => - Some(MoveStart(room.origin, room.roomType)) + Some(MoveStart(room.origin, room)) case _ => None } ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala index ccc425c0..656546ee 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala @@ -42,29 +42,7 @@ final case class CreatorModel(rooms: Batch[Room], monsters: Batch[ScenarioMonste object CreatorModel: def apply(): CreatorModel = CreatorModel( - Batch( - Room(RoomType.RoomA1A, Point.zero, 0) - ), - Batch( - ScenarioMonster( - MonsterType.AestherAshblade, - Point(2, 2), - MonsterLevel.None, - MonsterLevel.Normal, - MonsterLevel.Elite - ), - ScenarioMonster( - MonsterType.AestherAshblade, - Point(3, 2), - MonsterLevel.None, - MonsterLevel.Normal, - MonsterLevel.Elite - ) - ), - Batch( - BoardOverlay(1, Obstacle.Boulder2, Point(0, 0), 0), - BoardOverlay(2, Obstacle.Boulder2, Point(2, 0), 0), - BoardOverlay(3, Treasure.Coin(BaseGame.Gloomhaven, 1), Point(1, 3), 0), - BoardOverlay(4, Token(BaseGame.Gloomhaven, 'a'), Point(3, 3), 0) - ) + Batch.empty, + Batch.empty, + Batch.empty ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorViewModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorViewModel.scala index 9efa24eb..4790902c 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorViewModel.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorViewModel.scala @@ -2,10 +2,16 @@ package vgb.game.models.sceneModels import indigo.* import vgb.game.models.DragData +import vgb.common.RoomType +import vgb.common.BoardOverlayType +import vgb.common.MonsterType -final case class CreatorViewModel(dragging: Option[DragData]) { +final case class CreatorViewModel( + initialDragger: Option[RoomType | BoardOverlayType | MonsterType], + dragging: Option[DragData] +) { val camera = Camera.Fixed(Point(-200, -200)) } object CreatorViewModel: - def apply(): CreatorViewModel = CreatorViewModel(None) + def apply(): CreatorViewModel = CreatorViewModel(None, None) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala index 4ab2b24e..4a6a3c99 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -60,26 +60,36 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg context: SceneContext[Size], model: SceneModel ): GlobalEvent => Outcome[SceneModel] = { + case SceneEvent.SceneChange(_, to, _) => + if to == name then + Outcome(model) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent + .Send(CreatorMsgType.UpdateDragMenu(DragMenuComponent.getForModel(model))) + ) + else Outcome(model) case MoveEnd(newPos, d) => - d match { - case o: BoardOverlay => - Outcome( + val newModel = + d match { + case o: BoardOverlay => model.copy(overlays = GameRules.moveOverlay(newPos, o, model.overlays, model.cellMap)) - ) - case m: ScenarioMonster => - Outcome( + + case m: ScenarioMonster => model.copy(monsters = GameRules.moveMonster(newPos, m, model.monsters, model.cellMap)) - ) - case r: RoomType => - Outcome( + + case r: Room => model.copy(rooms = - model.rooms.map(room => - if room.roomType == r then room.copy(origin = newPos) - else room - ) + model.rooms + .filter(room => room.roomType != r.roomType) + :+ r.copy(origin = newPos) ) - ) - } + } + + Outcome(newModel) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent + .Send(CreatorMsgType.UpdateDragMenu(DragMenuComponent.getForModel(newModel))) + ) case tyrianSubSystem.TyrianEvent.Receive(msg) => msg match { case msg: CreatorMsgType => @@ -121,23 +131,46 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg .Send(GeneralMsgType.CloseContextMenu) ) case MouseEvent.Move(p) => - viewModel.dragging match { + val pos = Hexagon.screenPosToEvenRow(HexComponent.height, p + viewModel.camera.position).toPoint + val draggingData = + viewModel.dragging.orElse( + viewModel.initialDragger match { + case Some(d) => + val item = d match { + case r: RoomType => Room(r, pos, 0) + case m: MonsterType => + ScenarioMonster( + m, + pos, + MonsterLevel.None, + MonsterLevel.None, + MonsterLevel.None + ) + case o: BoardOverlayType => BoardOverlay(0, o, pos, 0) + } + Some(DragData(pos, pos, item, true)) + case None => None + } + ) + draggingData match { case Some(d) => - val pos = Hexagon.screenPosToEvenRow(HexComponent.height, p + viewModel.camera.position).toPoint val isValid = d.dragger match { - case r: RoomType => true + case r: Room => true case o: BoardOverlay => GameRules.isValidOverlayPos(pos, o, model.cellMap) case m: ScenarioMonster => GameRules.isValidMonsterPos(pos, m, model.cellMap) } if isValid then Outcome( - viewModel.copy(dragging = Some(d.copy(pos = pos, hasMoved = d.hasMoved || (d.originalPos != d.pos)))) + viewModel.copy( + dragging = Some(d.copy(pos = pos, hasMoved = d.hasMoved || (d.originalPos != d.pos))), + initialDragger = None + ) ) else Outcome(viewModel) case None => Outcome(viewModel) } - case MouseEvent.Click(p) => + case MouseEvent.MouseUp(p, MouseButton.LeftMouseButton) => viewModel.dragging match { case Some(d) if d.originalPos != d.pos => Outcome(viewModel.copy(dragging = None)) @@ -161,6 +194,8 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg ) ) } + case tyrianSubSystem.TyrianEvent.Receive(msg) => + updateViewModelFromTyrian(context, viewModel, msg) case _ => Outcome(viewModel) } @@ -182,8 +217,8 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg viewModel.dragging match { case Some(d) if d.originalPos != d.pos => d.dragger match { - case r1: RoomType => r1 != r.roomType - case _ => true + case r1: Room => r1.roomType != r.roomType + case _ => true } case _ => true } @@ -223,49 +258,16 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg case Some(d) if d.originalPos != d.pos => d.dragger match { case m: ScenarioMonster => - model.monsters.find(m1 => m1 == m) match { - case Some(m) => - MonsterComponent.render(m.copy(initialPosition = d.pos), cellMap) - case None => Layer() - } + MonsterComponent.render(m.copy(initialPosition = d.pos), cellMap) case o: BoardOverlay => - model.overlays.find(o1 => o1.id == o.id) match { - case Some(o) => BoardOverlayComponent.render(o.copy(origin = d.pos), cellMap) - case None => Layer() - } - case r: RoomType => - model.rooms.find(r1 => r1.roomType == r) match { - case Some(r) => RoomComponent.render(r.copy(origin = d.pos), viewModel.camera, false) - case None => Layer() - } + IndigoLogger.consoleLog(d.pos.toString()) + BoardOverlayComponent.render(o.copy(origin = d.pos), cellMap) + case r: Room => + RoomComponent.render(r.copy(origin = d.pos), viewModel.camera, false) } case _ => Layer() } ) - /*.addLayer( - Layer( - Batch.fromArray( - (0 until 10).toArray - .map(x => - (0 until 10).toArray - .map(y => - HexComponent.render( - Point(x, y), - cellMap.get(Point(x, y)) match { - case Some(flags) => - if (flags & Flag.Monster.value) != 0 then RGBA(1, 0, 0, 0.5) - else if (flags & Flag.Obstacle.value) != 0 then RGBA(0, 0, 1, 0.5) - else if (flags & Flag.Room.value) != 0 then RGBA(0, 1, 0, 0.5) - else RGBA.Zero - case None => RGBA.Zero - } - ) - ) - ) - .flatten - ) - ) - )*/ .withCamera(viewModel.camera) ) @@ -314,5 +316,19 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg case None => Outcome(model) } - case _ => Outcome(model) + case _ => + Outcome(model) + } + + def updateViewModelFromTyrian( + context: SceneContext[Size], + viewModel: SceneViewModel, + msg: GloomhavenMsg + ) = + msg match { + case CreatorMsgType.NewDragStart(item) => + Outcome(viewModel.copy(initialDragger = Some(item))) + case CreatorMsgType.DragEnd => + Outcome(viewModel.copy(initialDragger = None, dragging = None)) + case _ => Outcome(viewModel) } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala index dbd61e0f..a1a8284d 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -12,6 +12,12 @@ import vgb.ui.models.UiModel import vgb.common.MenuItem import vgb.common.MenuSeparator import vgb.ui.Msg +import vgb.common.DragDropSection +import indigo.shared.collections.Batch +import vgb.common.GeneralMsgType +import vgb.common.MonsterType +import vgb.common.BoardOverlayType +import vgb.common.RoomType object CreatorScene extends TyrianScene { type SceneModel = CreatorModel @@ -24,7 +30,18 @@ object CreatorScene extends TyrianScene { def update(msg: vgb.common.GloomhavenMsg, model: CreatorModel): (CreatorModel, Cmd[IO, GloomhavenMsg]) = msg match { - case CreatorMsgType.ChangeScenarioTitle(t) => (model.copy(scenarioTitle = t), Cmd.None) + case CreatorMsgType.SetSelectedDragSection(s) => (model.copy(dragMenuSelect = s), Cmd.None) + case CreatorMsgType.ChangeScenarioTitle(t) => (model.copy(scenarioTitle = t), Cmd.None) + case CreatorMsgType.UpdateDragMenu(menu) => + ( + model.copy( + dragMenu = menu, + dragMenuSelect = + if model.dragMenuSelect == "" then menu.headOption.map(s => s.name).getOrElse("") + else model.dragMenuSelect + ), + Cmd.None + ) case _ => (model, Cmd.None) } @@ -48,7 +65,33 @@ object CreatorScene extends TyrianScene { def getBoardAdditions(model: CreatorModel): List[Html[Msg]] = List( div(`class` := "page-shadow")(), - div(`class` := "action-list")() + div(`class` := "action-list")( + model.dragMenu + .map(s => + section(`class` := (if s.name == model.dragMenuSelect then "active" else ""))( + header(onClick(Msg.IndigoReceive(CreatorMsgType.SetSelectedDragSection(s.name))))(s.name), + ul(`class` := s.name.toLowerCase().replace(".", ""))( + s.items + .map(i => + li( + draggable := true, + `class` := (if i.dragging then "dragging" else ""), + onDragStart(Msg.IndigoSend(CreatorMsgType.NewDragStart(i.item))), + onDragEnd(Msg.IndigoSend(CreatorMsgType.DragEnd)) + )( + i.item match { + case m: MonsterType => m.name + case o: BoardOverlayType => o.toString() + case r: RoomType => s"""Map tile ${i.item.toString()}""" + } + ) + ) + .toList + ) + ) + ) + .toList + ) ) } @@ -56,6 +99,8 @@ final case class CreatorModel( scenarioTitle: String, mainMenu: Menu, showMainMenu: Boolean, + dragMenu: Batch[DragDropSection], + dragMenuSelect: String, contextMenu: Option[(Point, Menu)] ) extends UiModel { def updateContextMenu(menu: Option[(Point, Menu)]): UiModel = @@ -74,5 +119,7 @@ object CreatorModel: .add(Some(MenuItem("Import", CreatorMsgType.ShowImportDialog))) .add(MenuSeparator()), false, + Batch.empty, + "", None ) diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss index aafa1c8f..4cf5d908 100644 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss @@ -97,6 +97,8 @@ html { li { padding: 0.2rem 1.2rem; + user-select: none; + -webkit-user-select: none; img { max-width: 45px; From 26255820af9ecd400da23f2d4651e49beef5714e Mon Sep 17 00:00:00 2001 From: David North Date: Tue, 4 Jul 2023 08:07:53 +0100 Subject: [PATCH 54/60] Adds storage capability The creator now saves the state of the model (but doesn't yet load it) --- VirtualGloomhavenBoard/Indigo/build.sc | 6 +- .../src/vgb/common/BoardOverlayType.scala | 42 +++- .../Indigo/vgb-game/src/vgb/game/Main.scala | 4 +- .../src/vgb/game/models/BoardOverlay.scala | 16 +- .../src/vgb/game/models/GameRules.scala | 16 +- .../src/vgb/game/models/Placeable.scala | 4 +- .../vgb-game/src/vgb/game/models/Room.scala | 4 +- .../src/vgb/game/models/TileRotation.scala | 54 ++++++ .../components/BoardOverlayComponent.scala | 11 +- .../models/components/RoomComponent.scala | 2 +- .../models/sceneModels/CreatorModel.scala | 31 +-- .../vgb/game/models/storage/CellStorage.scala | 10 + .../game/models/storage/CreatorStorage.scala | 21 ++ .../game/models/storage/OverlayStorage.scala | 181 ++++++++++++++++++ .../vgb/game/models/storage/RoomStorage.scala | 25 +++ .../storage/ScenarioMonsterStorage.scala | 23 +++ .../src/vgb/game/scenes/CreatorScene.scala | 37 +++- .../src/vgb/ui/scenes/CreatorScene.scala | 5 +- .../Indigo/wwwroot/scss/_context-menu.scss | 1 + 19 files changed, 444 insertions(+), 49 deletions(-) create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CellStorage.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala diff --git a/VirtualGloomhavenBoard/Indigo/build.sc b/VirtualGloomhavenBoard/Indigo/build.sc index 24cdafef..b4ce5ab7 100644 --- a/VirtualGloomhavenBoard/Indigo/build.sc +++ b/VirtualGloomhavenBoard/Indigo/build.sc @@ -57,6 +57,7 @@ trait VgbModule extends ScalaJSModule { val indigoVersion = "0.15.0-RC2" val tyrianVersion = "0.7.1" + val circeVersion = "0.14.1" def ivyDeps = Agg( @@ -65,7 +66,10 @@ trait VgbModule extends ScalaJSModule { ivy"io.indigoengine::indigo-json-circe::$indigoVersion", ivy"io.indigoengine::indigo::$indigoVersion", ivy"io.indigoengine::indigo-extras::$indigoVersion", - ivy"org.scala-js:scalajs-java-securerandom_sjs1_2.13:1.0.0" + ivy"org.scala-js:scalajs-java-securerandom_sjs1_2.13:1.0.0", + ivy"io.circe::circe-core::$circeVersion", + ivy"io.circe::circe-generic::$circeVersion", + ivy"io.circe::circe-parser::$circeVersion" ) override def esFeatures: T[ESFeatures] = T { diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala index ec6bad1b..b81e8d2c 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala @@ -10,31 +10,48 @@ trait BoardOverlayType: val baseGame: BaseGame val cells: Batch[Point] val flag: Flag - val name: String = s"""${baseGame.shortName}-${this}""" - val assetName: AssetName = AssetName(name) + val verticalAssetName: Option[AssetName] + val name: String = this + .toString() + .toCharArray() + .foldLeft("")((s, c) => if c >= '0' && c <= 'Z' then s + " " + c else s + c) + .trim() + val assetName: AssetName = AssetName(s"""${baseGame.shortName}-${name.toLowerCase().replace(" ", "-")}""") enum DifficultTerrain( val baseGame: BaseGame, val cells: Batch[Point] ) extends BoardOverlayType: - val flag: Flag = Flag.DifficultTerrain + val flag: Flag = Flag.DifficultTerrain + val verticalAssetName = None case Rubble extends DifficultTerrain(BaseGame.Gloomhaven, Batch(Point(0, 0))) -enum Door( +enum Corridor( val baseGame: BaseGame, val cells: Batch[Point] +) extends BoardOverlayType: + val flag: Flag = Flag.Corridor + val verticalAssetName = None + case Altar extends Corridor(BaseGame.Gloomhaven, Batch(Point(0, 0))) + +enum Door( + val baseGame: BaseGame, + val cells: Batch[Point], + val verticalAssetName: Option[AssetName] ) extends BoardOverlayType: val flag: Flag = Flag.Door - case Altar extends Door(BaseGame.Gloomhaven, Batch(Point(0, 0))) + case Altar extends Door(BaseGame.Gloomhaven, Batch(Point(0, 0)), None) enum Hazard(val baseGame: BaseGame, val cells: Batch[Point]) extends BoardOverlayType: - val flag: Flag = Flag.Hazard + val flag: Flag = Flag.Hazard + val verticalAssetName = None case HotCoals extends Hazard(BaseGame.Gloomhaven, Batch(Point(0, 0))) case Thorns extends Hazard(BaseGame.Gloomhaven, Batch(Point(0, 0))) enum Highlight(val baseGame: BaseGame, val colour: RGB) extends BoardOverlayType: val cells: Batch[Point] = Batch(Point(0, 0)) val flag: Flag = Flag.Highlight + val verticalAssetName = None case Red extends Highlight(BaseGame.Gloomhaven, RGB.Red) case Orange extends Highlight(BaseGame.Gloomhaven, RGB.Orange) case Yellow extends Highlight(BaseGame.Gloomhaven, RGB.Yellow) @@ -43,25 +60,30 @@ enum Highlight(val baseGame: BaseGame, val colour: RGB) extends BoardOverlayType case Indigo extends Highlight(BaseGame.Gloomhaven, RGB.Indigo) enum Obstacle(val baseGame: BaseGame, val cells: Batch[Point]) extends BoardOverlayType: - val flag: Flag = Flag.Obstacle + val flag: Flag = Flag.Obstacle + val verticalAssetName = None case Boulder2 extends Obstacle(BaseGame.Gloomhaven, Batch(Point(0, 0), Point(1, 0))) final case class Rift(val baseGame: BaseGame) extends BoardOverlayType { val cells: Batch[Point] = Batch(Point(0, 0)) val flag: Flag = Flag.Rift + val verticalAssetName = None } enum StartingLocation(val baseGame: BaseGame) extends BoardOverlayType: val cells: Batch[Point] = Batch(Point(0, 0)) val flag: Flag = Flag.StartingLocation + val verticalAssetName = None case Gloomhaven extends StartingLocation(BaseGame.Gloomhaven) enum Trap(val baseGame: BaseGame, val cells: Batch[Point]) extends BoardOverlayType: - val flag: Flag = Flag.Trap + val flag: Flag = Flag.Trap + val verticalAssetName = None case BearTrap extends Trap(BaseGame.Gloomhaven, Batch(Point(0, 0))) enum Treasure(val flag: Flag) extends BoardOverlayType: val cells: Batch[Point] = Batch(Point(0, 0)) + val verticalAssetName = None override def toString(): String = this match case Chest(_, _) => "Chest" @@ -73,8 +95,10 @@ enum Treasure(val flag: Flag) extends BoardOverlayType: final case class Token(val baseGame: BaseGame, val letter: Char) extends BoardOverlayType: val cells: Batch[Point] = Batch(Point(0, 0)) val flag: Flag = Flag.Token + val verticalAssetName = None override def toString(): String = s"""Token (${letter})""" enum Wall(val baseGame: BaseGame, val cells: Batch[Point]) extends BoardOverlayType: - val flag: Flag = Flag.Wall + val flag: Flag = Flag.Wall + val verticalAssetName = None case Rock extends Wall(BaseGame.Gloomhaven, Batch(Point(0, 0))) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala index 9ce52f4a..5fb2f64d 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala @@ -50,8 +50,8 @@ final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) .withAssets( AssetType.Image(AssetName("gh-a1a"), AssetPath("img/map-tiles/gloomhaven/a1a.webp")), AssetType.Image(AssetName("aesther-ashblade"), AssetPath("img/monsters/aesther-ashblade.webp")), - AssetType.Image(AssetName("gh-Boulder2"), AssetPath("img/overlays/obstacle-boulder-2.webp")), - AssetType.Image(AssetName("gh-Coin"), AssetPath("img/overlays/treasure-coin.webp")), + AssetType.Image(AssetName("gh-boulder-2"), AssetPath("img/overlays/obstacle-boulder-2.webp")), + AssetType.Image(AssetName("gh-coin"), AssetPath("img/overlays/treasure-coin.webp")), AssetType.Image(AssetName("move-icon"), AssetPath("img/move-icon.webp")), AssetType.Image(AssetName("hex-border"), AssetPath("img/hex-border.webp")), AssetType.Font(AssetName("PirateOne"), AssetPath("fonts/PirataOne-Gloomhaven.woff2")) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala index a21e8bbb..249db306 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala @@ -2,12 +2,14 @@ package vgb.game.models import indigo.* import vgb.common.BoardOverlayType +import vgb.common.RoomType final case class BoardOverlay( id: Int, overlayType: BoardOverlayType, origin: Point, - numRotations: Byte + rotation: TileRotation, + linkedRooms: Option[Batch[RoomType]] ) extends Placeable { val maxPoint = overlayType.cells.foldLeft(Point.zero)((max, p) => max.max(p)) val minPoint = overlayType.cells.foldLeft(maxPoint)((min, p) => min.min(p)) @@ -16,8 +18,18 @@ final case class BoardOverlay( def rotate() = val rotatedOrigin = Hexagon.evenRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) + this.copy( origin = rotatedOrigin.toPoint, - numRotations = if numRotations == 5 then 0 else (numRotations + 1).toByte + rotation = rotation.nextRotation(overlayType.verticalAssetName != None) ) } + +object BoardOverlay: + def apply( + id: Int, + overlayType: BoardOverlayType, + origin: Point, + rotation: TileRotation + ): BoardOverlay = + BoardOverlay(id, overlayType, origin, rotation, None) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala index 3153008b..61a3dfcb 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala @@ -25,7 +25,10 @@ object GameRules: ): Batch[BoardOverlay] = if (isValidOverlayPos(newPos, overlay, cellMap)) overlays.filter(o => o.id != overlay.id) - :+ overlay.copy(origin = newPos, id = if overlay.id == 0 then overlays.length + 1 else overlay.id) + :+ overlay.copy( + origin = newPos, + id = if overlay.id == 0 then (overlays.foldLeft(0)((i, o) => Math.max(o.id, i))) + 1 else overlay.id + ) else overlays @@ -42,7 +45,7 @@ object GameRules: } ) - val newOverlay = nextValidOverlayRotation(overlay.numRotations, overlay, newMap) + val newOverlay = nextValidOverlayRotation(overlay.rotation, overlay, newMap) overlays.map(o => if o.id == overlay.id then newOverlay else o) def isValidMonsterPos(newPos: Point, monster: ScenarioMonster, cellMap: Map[Point, Int]): Boolean = @@ -69,10 +72,13 @@ object GameRules: canPlaceOverlay(overlay.copy(origin = newPos), newMap) - def nextValidOverlayRotation(initialRotation: Byte, overlay: BoardOverlay, cellMap: Map[Point, Int]): BoardOverlay = + def nextValidOverlayRotation( + initialRotation: TileRotation, + overlay: BoardOverlay, + cellMap: Map[Point, Int] + ): BoardOverlay = val rotatedOverlay = overlay.rotate() - if rotatedOverlay.overlayType.flag == Flag.Coin || initialRotation == rotatedOverlay.numRotations then - rotatedOverlay + if rotatedOverlay.overlayType.flag == Flag.Coin || initialRotation == rotatedOverlay.rotation then rotatedOverlay else if canPlaceOverlay(rotatedOverlay, cellMap) then rotatedOverlay else nextValidOverlayRotation(initialRotation, rotatedOverlay, cellMap) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala index 72710121..707b39a9 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala @@ -3,7 +3,7 @@ package vgb.game.models import indigo.* trait Placeable: - val numRotations: Byte + val rotation: TileRotation val origin: Point val minPoint: Point val maxPoint: Point @@ -17,7 +17,7 @@ trait Placeable: .evenRowRotate( Vector2.fromPoint(localPoint), Vector2.fromPoint(minPoint), - numRotations + rotation.toByte() ) .toPoint diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala index e7ccc676..27e4670b 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala @@ -6,7 +6,7 @@ import vgb.common.RoomType final case class Room( roomType: RoomType, origin: Point, - numRotations: Byte + rotation: TileRotation ) extends Placeable { val maxPoint = roomType.cells.foldLeft(Point.zero)((max, p) => max.max(p)) val minPoint = roomType.cells.foldLeft(maxPoint)((min, p) => min.min(p)) @@ -17,6 +17,6 @@ final case class Room( Hexagon.evenRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) this.copy( origin = rotatedOrigin.toPoint, - numRotations = if numRotations == 5 then 0 else (numRotations + 1).toByte + rotation = rotation.nextRotation(false) ) } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala new file mode 100644 index 00000000..cfb624b7 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala @@ -0,0 +1,54 @@ +package vgb.game.models + +enum TileRotation: + case Default, Horizontal, Vertical, VerticalReverse, DiagonalLeft, + DiagonalRight, DiagonalLeftReverse, DiagonalRightReverse + + def toByte(): Byte = + this match { + case Default => 0 + case DiagonalLeft => 1 + case Vertical => 0 + case DiagonalRight => 2 + case Horizontal => 3 + case DiagonalLeftReverse => 4 + case VerticalReverse => 3 + case DiagonalRightReverse => 5 + } + + def nextRotation(hasVertical: Boolean) = + this match { + case Default => DiagonalLeft + case DiagonalLeft => if hasVertical then Vertical else DiagonalRight + case Vertical => DiagonalRight + case DiagonalRight => Horizontal + case Horizontal => DiagonalLeftReverse + case DiagonalLeftReverse => if hasVertical then VerticalReverse else DiagonalRightReverse + case VerticalReverse => DiagonalRightReverse + case DiagonalRightReverse => Default + } + + override def toString() = + this match { + case Default => "default" + case DiagonalLeft => "diagonal-left" + case Vertical => "vertical" + case DiagonalRight => "diagonal-right" + case Horizontal => "horizontal" + case DiagonalLeftReverse => "diagonal-left-reverse" + case VerticalReverse => "vertical-reverse" + case DiagonalRightReverse => "diagonal-right-reverse" + } + +object TileRotation: + def fromString(dir: String) = + dir match { + case "diagonal-left" => DiagonalLeft + case "vertical" => Vertical + case "diagonal-right" => DiagonalRight + case "horizontal" => Horizontal + case "diagonal-left-reverse" => DiagonalLeftReverse + case "vertical-reverse" => VerticalReverse + case "diagonal-right-reverse" => DiagonalRightReverse + case _ => Default + } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala index c51a4b24..f1b0b7b1 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala @@ -3,6 +3,7 @@ package vgb.game.models.components import indigo.* import vgb.game.models.BoardOverlay import vgb.game.models.Hexagon +import vgb.game.models.TileRotation import indigo.shared.scenegraph.Shape.Circle import vgb.game.models.LayerDepths import vgb.common.Treasure @@ -60,10 +61,16 @@ object BoardOverlayComponent: case t: Treasure.Coin => Size(90, 90) case _ => Size(156, 90) }, - Material.Bitmap(boardOverlay.overlayType.assetName) + Material.Bitmap( + (boardOverlay.rotation, boardOverlay.overlayType.verticalAssetName) match { + case (TileRotation.Vertical, Some(verticalAsset)) => verticalAsset + case (TileRotation.VerticalReverse, Some(verticalAsset)) => verticalAsset + case _ => boardOverlay.overlayType.assetName + } + ) ) .withRef(offset) - .rotateTo(Radians.fromDegrees(60 * boardOverlay.numRotations)) + .rotateTo(Radians.fromDegrees(60 * boardOverlay.rotation.toByte())) Layer( boardOverlay.overlayType match { case t: Treasure.Coin => diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala index f21ce573..11000e0e 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala @@ -31,7 +31,7 @@ object RoomComponent: Batch( Graphic(room.roomType.size, Material.Bitmap(room.roomType.assetName)) .withRef(offset) - .rotateTo(Radians.fromDegrees(60 * room.numRotations)) + .rotateTo(Radians.fromDegrees(60 * room.rotation.toByte())) .moveTo(origin) ) ++ (if moveable then diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala index 656546ee..f3385b3e 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala @@ -1,21 +1,23 @@ package vgb.game.models.sceneModels +import io.circe.* +import io.circe.generic.auto.* +import io.circe.parser.* +import io.circe.syntax.* import indigo.* +import vgb.common.* +import vgb.game.models.BoardOverlay import vgb.game.models.Room import vgb.game.models.ScenarioMonster +import vgb.game.models.storage.CreatorStorage -// Remove these later -import vgb.common.RoomType -import vgb.common.MonsterType -import vgb.common.Obstacle -import vgb.common.Treasure -import vgb.common.Token -import vgb.common.MonsterLevel -import vgb.game.models.BoardOverlay -import vgb.common.Flag -import vgb.common.BaseGame - -final case class CreatorModel(rooms: Batch[Room], monsters: Batch[ScenarioMonster], overlays: Batch[BoardOverlay]) { +final case class CreatorModel( + scenarioTitle: String, + baseGame: BaseGame, + rooms: Batch[Room], + monsters: Batch[ScenarioMonster], + overlays: Batch[BoardOverlay] +) { val cellMap: Map[Point, Int] = (rooms .foldLeft(Batch.empty[(Point, Int)])((batch, room) => room.worldCells @@ -37,11 +39,16 @@ final case class CreatorModel(rooms: Batch[Room], monsters: Batch[ScenarioMonste } } ) + + override def toString(): String = + CreatorStorage.fromModel(this).asJson.deepDropNullValues.noSpaces } object CreatorModel: def apply(): CreatorModel = CreatorModel( + "", + BaseGame.Gloomhaven, Batch.empty, Batch.empty, Batch.empty diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CellStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CellStorage.scala new file mode 100644 index 00000000..2fd42978 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CellStorage.scala @@ -0,0 +1,10 @@ +package vgb.game.models.storage + +import indigo.shared.datatypes.Point + +final case class CellStorage(x: Int, y: Int): + def toList = List(x, y) + +object CellStorage: + def fromPoint(p: Point) = + CellStorage(p.x, p.y) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala new file mode 100644 index 00000000..f0d47b09 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala @@ -0,0 +1,21 @@ +package vgb.game.models.storage + +import vgb.game.models.sceneModels.CreatorModel + +final case class CreatorStorage( + scenarioTitle: String, + baseGame: Option[String], + roomData: List[RoomStorage], + overlays: List[OverlayStorage], + monsters: List[ScenarioMonsterStorage] +) + +object CreatorStorage: + def fromModel(model: CreatorModel) = + CreatorStorage( + model.scenarioTitle, + Some(model.baseGame.toString()), + model.rooms.map(r => RoomStorage.fromModel(r)).toList, + model.overlays.map(o => OverlayStorage.fromModel(o)).toList, + model.monsters.map(m => ScenarioMonsterStorage.fromModel(m)).toList + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala new file mode 100644 index 00000000..83dfa6e3 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala @@ -0,0 +1,181 @@ +package vgb.game.models.storage + +import vgb.common.* +import vgb.game.models.BoardOverlay +import indigo.shared.collections.Batch +import indigo.shared.datatypes.RGB + +final case class OverlayStorage( + ref: OverlayStorageRef, + id: Int, + direction: String, + cells: List[List[Int]] +) + +final case class OverlayStorageRef( + `type`: String, + subType: Option[String], + material: Option[String], + size: Option[Byte], + links: Option[List[String]], + colour: Option[String], + value: Option[Char], + id: Option[String], + amount: Option[Byte] +) + +object OverlayStorage: + def fromModel(overlay: BoardOverlay) = + OverlayStorage( + getRefForType(overlay), + overlay.id, + overlay.rotation.toString(), + overlay.worldCells.map(c => CellStorage.fromPoint(c).toList).toList + ) + + private def getRefForType(overlay: BoardOverlay) = + overlay.overlayType match { + case c: Corridor => + OverlayStorageRef( + "door", + "corridor", + c.name, + c.cells.length.toByte, + overlay.linkedRooms.getOrElse(Batch.empty).toList.map(r => r.toString()) + ) + case o: DifficultTerrain => OverlayStorageRef("difficult-terrain", o.name) + case d: Door => + OverlayStorageRef( + "door", + d.name, + overlay.linkedRooms.getOrElse(Batch.empty).toList.map(r => r.toString()) + ) + case h: Hazard => OverlayStorageRef("hazard", h.name) + case h: Highlight => OverlayStorageRef("highlight", h.colour) + case o: Obstacle => OverlayStorageRef("obstacle", o.name) + case r: Rift => OverlayStorageRef("rift") + case s: StartingLocation => OverlayStorageRef("starting-location") + case t: Trap => OverlayStorageRef("trap", t.name) + case t: Treasure => + t match { + case t: Treasure.Chest => OverlayStorageRef("treasure", "chest", t.treasureType) + case t: Treasure.Coin => OverlayStorageRef("treasure", "coin", t.amount) + } + case Token(_, value) => OverlayStorageRef("token", value) + case w: Wall => OverlayStorageRef("wall", w.name) + } + +object OverlayStorageRef: + def apply(overlayType: String): OverlayStorageRef = + OverlayStorageRef( + overlayType, + None, + None, + None, + None, + None, + None, + None, + None + ) + + def apply(overlayType: String, subType: String): OverlayStorageRef = + OverlayStorageRef( + overlayType, + Some(subType.toLowerCase().replace(" ", "-")), + None, + None, + None, + None, + None, + None, + None + ) + + def apply(overlayType: String, colour: RGB): OverlayStorageRef = + OverlayStorageRef( + overlayType, + None, + None, + None, + None, + Some(colour.toHexString), + None, + None, + None + ) + + def apply(overlayType: String, value: Char): OverlayStorageRef = + OverlayStorageRef( + overlayType, + None, + None, + None, + None, + None, + Some(value), + None, + None + ) + + def apply(overlayType: String, subType: String, mapRefs: List[String]): OverlayStorageRef = + OverlayStorageRef( + overlayType, + Some(subType.toLowerCase().replace(" ", "-")), + None, + None, + Some(mapRefs), + None, + None, + None, + None + ) + + def apply(overlayType: String, subType: String, amount: Byte): OverlayStorageRef = + OverlayStorageRef( + overlayType, + Some(subType.toLowerCase().replace(" ", "-")), + None, + None, + None, + None, + None, + None, + Some(amount) + ) + + def apply(overlayType: String, subType: String, treasureType: TreasureChestType): OverlayStorageRef = + OverlayStorageRef( + overlayType, + Some(subType.toLowerCase().replace(" ", "-")), + None, + None, + None, + None, + None, + Some(treasureType match { + case TreasureChestType.Goal => "goal" + case TreasureChestType.Locked => "locked" + case TreasureChestType.Normal(i) => i.toString() + }), + None + ) + + def apply( + overlayType: String, + subType: String, + material: String, + size: Byte, + mapRefs: List[String] + ): OverlayStorageRef = + OverlayStorageRef( + overlayType, + Some(subType.toLowerCase().replace(" ", "-")), + Some(material.toLowerCase().replace(" ", "-")), + Some(size), + Some(mapRefs), + None, + None, + None, + None + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala new file mode 100644 index 00000000..28e12b0e --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala @@ -0,0 +1,25 @@ +package vgb.game.models.storage + +import vgb.game.models.Room + +final case class RoomStorage( + data: RoomDataStorage, + rotationPoint: CellStorage +) + +final case class RoomDataStorage( + ref: String, + origin: CellStorage, + turns: Int +) + +object RoomStorage: + def fromModel(room: Room) = + RoomStorage( + RoomDataStorage( + room.roomType.mapRef, + CellStorage.fromPoint(room.origin), + room.rotation.toByte() + ), + CellStorage.fromPoint(room.rotationPoint) + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala new file mode 100644 index 00000000..dee9e475 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala @@ -0,0 +1,23 @@ +package vgb.game.models.storage + +import vgb.game.models.ScenarioMonster + +final case class ScenarioMonsterStorage( + monster: String, + initialX: Int, + initialY: Int, + twoPlayer: String, + threePlayer: String, + fourPlayer: String +) + +object ScenarioMonsterStorage: + def fromModel(monster: ScenarioMonster) = + ScenarioMonsterStorage( + monster.monsterType.assetName.toString(), + monster.initialPosition.x, + monster.initialPosition.y, + monster.twoPlayerLevel.toString().toLowerCase(), + monster.threePlayerLevel.toString().toLowerCase(), + monster.fourPlayerLevel.toString().toLowerCase() + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala index 4a6a3c99..ed8035cd 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -13,6 +13,7 @@ import vgb.game.MoveStart import vgb.game.MoveEnd import vgb.game.models.Hexagon import vgb.game.models.ScenarioMonster +import vgb.game.models.TileRotation import vgb.game.models.components.* import vgb.game.models.sceneModels.CreatorModel import vgb.game.models.sceneModels.CreatorViewModel @@ -30,7 +31,8 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg type SceneModel = CreatorModel type SceneViewModel = CreatorViewModel - val name: SceneName = SceneName("creator-scene") + val name: SceneName = SceneName("creator-scene") + val saveSlot: String = "creator" val modelLens: Lens[GameModel, CreatorModel] = Lens( @@ -90,10 +92,21 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg tyrianSubSystem.TyrianEvent .Send(CreatorMsgType.UpdateDragMenu(DragMenuComponent.getForModel(newModel))) ) + .addGlobalEvents(StorageEvent.Save(saveSlot, newModel.toString())) case tyrianSubSystem.TyrianEvent.Receive(msg) => msg match { case msg: CreatorMsgType => - updateModelFromTyrian(context, model, msg) + val outcome = updateModelFromTyrian(context, model, msg) + + outcome.flatMap(m => + Outcome(m) + .addGlobalEvents( + if m != model then + outcome.globalEventsOrNil :+ + StorageEvent.Save(saveSlot, m.toString()) + else outcome.globalEventsOrNil + ) + ) case _ => Outcome(model) } @@ -137,16 +150,16 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg viewModel.initialDragger match { case Some(d) => val item = d match { - case r: RoomType => Room(r, pos, 0) + case r: RoomType => Room(r, pos, TileRotation.Default) case m: MonsterType => ScenarioMonster( m, pos, - MonsterLevel.None, - MonsterLevel.None, - MonsterLevel.None + MonsterLevel.Normal, + MonsterLevel.Normal, + MonsterLevel.Normal ) - case o: BoardOverlayType => BoardOverlay(0, o, pos, 0) + case o: BoardOverlayType => BoardOverlay(0, o, pos, TileRotation.Default) } Some(DragData(pos, pos, item, true)) case None => None @@ -260,7 +273,6 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg case m: ScenarioMonster => MonsterComponent.render(m.copy(initialPosition = d.pos), cellMap) case o: BoardOverlay => - IndigoLogger.consoleLog(d.pos.toString()) BoardOverlayComponent.render(o.copy(origin = d.pos), cellMap) case r: Room => RoomComponent.render(r.copy(origin = d.pos), viewModel.camera, false) @@ -277,6 +289,13 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg msg: CreatorMsgType ) = msg match { + case CreatorMsgType.ChangeScenarioTitle(t) => + val newTitle = t.slice(0, 30) + Outcome(model.copy(scenarioTitle = newTitle)) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent.Send(CreatorMsgType.ChangeScenarioTitle(newTitle)) + ) + case CreatorMsgType.ChangeMonsterLevel(p, m, playerNum, level) => model.monsters.find(m1 => p == m1.initialPosition && m == m1.monsterType) match { case Some(m) => @@ -310,7 +329,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg Hexagon.evenRowRotate(Vector2.fromPoint(room.origin), Vector2.fromPoint(room.rotationPoint), 1) val newRoom = room.copy( origin = rotatedOrigin.toPoint, - numRotations = if room.numRotations == 5 then 0 else (room.numRotations + 1).toByte + rotation = room.rotation.nextRotation(false) ) Outcome(model.copy(rooms = model.rooms.map(r1 => if r1 == room then newRoom else r1))) case None => Outcome(model) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala index a1a8284d..c1b8aa04 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -55,8 +55,9 @@ object CreatorScene extends TyrianScene { `type` := "text", placeholder := "Enter Scenario Title", maxLength := 30, + value := model.scenarioTitle, onInput(_ match { - case t => Msg.IndigoReceive(CreatorMsgType.ChangeScenarioTitle(t)) + case t => Msg.IndigoSend(CreatorMsgType.ChangeScenarioTitle(t)) }) ) ) @@ -81,7 +82,7 @@ object CreatorScene extends TyrianScene { )( i.item match { case m: MonsterType => m.name - case o: BoardOverlayType => o.toString() + case o: BoardOverlayType => o.name case r: RoomType => s"""Map tile ${i.item.toString()}""" } ) diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss index 23557ba2..506b215b 100644 --- a/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss @@ -26,6 +26,7 @@ padding: 0.2rem 1rem; border-radius: 0.2rem; position: relative; + user-select: none; &:hover { cursor: pointer; From fc35fa5cea4327c9d679d7c031f4ed90a826fd24 Mon Sep 17 00:00:00 2001 From: David North Date: Mon, 10 Jul 2023 08:08:33 +0100 Subject: [PATCH 55/60] A number of changes and fixes * Mill upgrade * Hexagon rotation is now odd row (to match legacy) * Legacy web storage now works after a fashion * Rotation is broken - it's unclear why at the moment * Added tests * Fixes CI --- VirtualGloomhavenBoard/Indigo/.mill-version | 2 +- .../src/vgb/common/BoardOverlayType.scala | 37 ++- .../src/vgb/common}/Hexagon.scala | 42 ++-- .../src/vgb/common/MonsterLevel.scala | 6 + .../vgb-common/src/vgb/common/RoomType.scala | 10 +- .../test/src/vgb/common/HexagonTests.scala | 91 +++++++ .../src/vgb/game/models/BoardOverlay.scala | 3 +- .../src/vgb/game/models/Placeable.scala | 3 +- .../vgb-game/src/vgb/game/models/Room.scala | 3 +- .../src/vgb/game/models/TileRotation.scala | 7 + .../components/BoardOverlayComponent.scala | 12 +- .../game/models/components/HexComponent.scala | 4 +- .../models/components/MonsterComponent.scala | 4 +- .../models/components/RoomComponent.scala | 14 +- .../models/sceneModels/CreatorModel.scala | 6 + .../game/models/storage/CreatorStorage.scala | 45 +++- .../game/models/storage/OverlayStorage.scala | 224 ++++++++++++++++-- .../vgb/game/models/storage/RoomStorage.scala | 22 +- .../storage/ScenarioMonsterStorage.scala | 26 +- .../src/vgb/game/scenes/CreatorScene.scala | 57 ++++- ci.sh | 24 +- 21 files changed, 549 insertions(+), 93 deletions(-) rename VirtualGloomhavenBoard/Indigo/{vgb-game/src/vgb/game/models => vgb-common/src/vgb/common}/Hexagon.scala (61%) create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala mode change 100644 => 100755 ci.sh diff --git a/VirtualGloomhavenBoard/Indigo/.mill-version b/VirtualGloomhavenBoard/Indigo/.mill-version index d9df1bbc..af88ba82 100644 --- a/VirtualGloomhavenBoard/Indigo/.mill-version +++ b/VirtualGloomhavenBoard/Indigo/.mill-version @@ -1 +1 @@ -0.11.0 +0.11.1 diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala index b81e8d2c..f94a24c3 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala @@ -3,9 +3,27 @@ package vgb.common import indigo.* enum TreasureChestType: + override def toString(): String = this match { + case Goal => "goal" + case Locked => "locked" + case Normal(i) => i.toString() + } + case Normal(val number: Byte) extends TreasureChestType case Goal, Locked +object TreasureChestType: + def fromString(str: String) = + str.toLowerCase() match { + case "goal" => Goal + case "locked" => Locked + case _ => + str.toByteOption match { + case Some(b) => Normal(b) + case None => Normal(0) + } + } + trait BoardOverlayType: val baseGame: BaseGame val cells: Batch[Point] @@ -16,7 +34,8 @@ trait BoardOverlayType: .toCharArray() .foldLeft("")((s, c) => if c >= '0' && c <= 'Z' then s + " " + c else s + c) .trim() - val assetName: AssetName = AssetName(s"""${baseGame.shortName}-${name.toLowerCase().replace(" ", "-")}""") + val codedName = name.toLowerCase().replace(" ", "-") + val assetName: AssetName = AssetName(s"""${baseGame.shortName}-${codedName}""") enum DifficultTerrain( val baseGame: BaseGame, @@ -48,16 +67,18 @@ enum Hazard(val baseGame: BaseGame, val cells: Batch[Point]) extends BoardOverla case HotCoals extends Hazard(BaseGame.Gloomhaven, Batch(Point(0, 0))) case Thorns extends Hazard(BaseGame.Gloomhaven, Batch(Point(0, 0))) -enum Highlight(val baseGame: BaseGame, val colour: RGB) extends BoardOverlayType: +final case class Highlight(val baseGame: BaseGame, val colour: RGB) extends BoardOverlayType: val cells: Batch[Point] = Batch(Point(0, 0)) val flag: Flag = Flag.Highlight val verticalAssetName = None - case Red extends Highlight(BaseGame.Gloomhaven, RGB.Red) - case Orange extends Highlight(BaseGame.Gloomhaven, RGB.Orange) - case Yellow extends Highlight(BaseGame.Gloomhaven, RGB.Yellow) - case Green extends Highlight(BaseGame.Gloomhaven, RGB.Green) - case Blue extends Highlight(BaseGame.Gloomhaven, RGB.Blue) - case Indigo extends Highlight(BaseGame.Gloomhaven, RGB.Indigo) + +object Highlight: + val Red = Highlight(BaseGame.Gloomhaven, RGB.Red) + val Orange = Highlight(BaseGame.Gloomhaven, RGB.Orange) + val Yellow = Highlight(BaseGame.Gloomhaven, RGB.Yellow) + val Green = Highlight(BaseGame.Gloomhaven, RGB.Green) + val Blue = Highlight(BaseGame.Gloomhaven, RGB.Blue) + val Indigo = Highlight(BaseGame.Gloomhaven, RGB.Indigo) enum Obstacle(val baseGame: BaseGame, val cells: Batch[Point]) extends BoardOverlayType: val flag: Flag = Flag.Obstacle diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Hexagon.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala similarity index 61% rename from VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Hexagon.scala rename to VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala index 7b9d1633..b506ae5f 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Hexagon.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala @@ -1,4 +1,4 @@ -package vgb.game.models +package vgb.common import indigo.shared.datatypes.Point import indigo.shared.datatypes.Vector2 @@ -21,8 +21,8 @@ object Hexagon: ) } - def screenPosToEvenRow(size: Int, pos: Point) = - axialToEvenRow(screenPosToAxial(size, pos)) + def screenPosToOddRow(size: Int, pos: Point) = + axialToOddRow(screenPosToAxial(size, pos)) def axialToScreenPos(size: Int, pos: Vector2) = val halfSize = size * 0.5; @@ -31,26 +31,26 @@ object Hexagon: (halfSize * threeOver2 * pos.y).toInt ) - def evenRowToScreenPos(size: Int, pos: Point) = - axialToScreenPos(size, evenRowToAxial(Vector2.fromPoint(pos))) + def oddRowToScreenPos(size: Int, pos: Point) = + axialToScreenPos(size, oddRowToAxial(Vector2.fromPoint(pos))) - def axialToEvenRow(pos: Vector2) = + def axialToOddRow(pos: Vector2) = Vector2( - pos.x + (pos.y + (pos.y.toInt & 1)) * 0.5, + pos.x + (pos.y - (pos.y.toInt & 1)) * 0.5, pos.y ) - def evenRowToAxial(pos: Vector2) = + def oddRowToAxial(pos: Vector2) = Vector2( - pos.x - (pos.y + (pos.y.toInt & 1)) * 0.5, + pos.x - (pos.y - (pos.y.toInt & 1)) * 0.5, pos.y ) - def cubeToEvenRow(pos: Vector3) = - Vector2(pos.x + (pos.y + (pos.y.toInt & 1)) * 0.5, pos.y) + def cubeToOddRow(pos: Vector3) = + Vector2(pos.x + (pos.y - (pos.y.toInt & 1)) * 0.5, pos.y) - def evenRowToCube(pos: Vector2) = - val newX = pos.x - (pos.y + (pos.y.toInt & 1)) * 0.5 + def oddRowToCube(pos: Vector2) = + val newX = pos.x - (pos.y - (pos.y.toInt & 1)) * 0.5 Vector3(newX, pos.y, -newX - pos.y) def cubeToAxial(pos: Vector3) = @@ -74,22 +74,22 @@ object Hexagon: else Vector3(q, r, -q - r) } - def evenRowRotate(origin: Vector2, rotationPoint: Vector2, numTurns: Byte): Vector2 = - val rotateResult = evenRowSingleRotate(origin, rotationPoint) + def oddRowRotate(origin: Vector2, rotationPoint: Vector2, numTurns: Byte): Vector2 = + val rotateResult = oddRowSingleRotate(origin, rotationPoint) numTurns match case 0 => origin case 1 => rotateResult case other if other < 0 => - evenRowRotate(rotateResult, rotationPoint, (other + 1).toByte) + oddRowRotate(rotateResult, rotationPoint, (other + 1).toByte) case other => - evenRowRotate(rotateResult, rotationPoint, (other - 1).toByte) + oddRowRotate(rotateResult, rotationPoint, (other - 1).toByte) - def evenRowSingleRotate(origin: Vector2, rotationPoint: Vector2): Vector2 = - val (originX, originY, originZ) = evenRowToCube(origin) match + def oddRowSingleRotate(origin: Vector2, rotationPoint: Vector2): Vector2 = + val (originX, originY, originZ) = oddRowToCube(origin) match case v => (v.x, v.y, v.z) - val (rotateX, rotateY, rotateZ) = evenRowToCube(rotationPoint) match + val (rotateX, rotateY, rotateZ) = oddRowToCube(rotationPoint) match case v => (v.x, v.y, v.z) val (rX, rY, rZ) = (-(originY - rotateY), -(originZ - rotateZ), -(originX - rotateX)) - cubeToEvenRow(Vector3(rX + rotateX, rY + rotateY, rZ + rotateZ)) + cubeToOddRow(Vector3(rX + rotateX, rY + rotateY, rZ + rotateZ)) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/MonsterLevel.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/MonsterLevel.scala index ba6d4f9c..cbd660f6 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/MonsterLevel.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/MonsterLevel.scala @@ -2,3 +2,9 @@ package vgb.common enum MonsterLevel: case None, Normal, Elite + +object MonsterLevel: + def fromString(str: String) = + MonsterLevel.values + .find(l => l.toString().toLowerCase() == str) + .getOrElse(None) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala index 6622f72d..b85eea06 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala @@ -11,15 +11,15 @@ enum RoomType(val baseGame: BaseGame, val mapRef: String, val offset: Point, val "a1a", Point(-13, -34), Batch( - Point(0, 0), - Point(1, 0), - Point(2, 0), - Point(3, 0), Point(0, 1), Point(1, 1), Point(2, 1), Point(3, 1), - Point(4, 1) + Point(0, 2), + Point(1, 2), + Point(2, 2), + Point(3, 2), + Point(4, 2) ), Size(432, 244) ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala new file mode 100644 index 00000000..ac5eb659 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala @@ -0,0 +1,91 @@ +package vgb.common + +import indigo.shared.datatypes.Vector2 + +class HexagonTests extends munit.FunSuite { + + test("should rotate (0, 2) 0 turn around 0, 0") { + assertEquals( + Vector2(0, 2), + Hexagon.oddRowRotate(Vector2(0, 2), Vector2(0, 0), 0) + ) + } + + test("should rotate (0, 2) 1 turn around 0, 0") { + assertEquals( + Vector2(-2, 1), + Hexagon.oddRowRotate(Vector2(0, 2), Vector2(0, 0), 1) + ) + } + + test("should rotate (-1, 0) 1 turns around 0, 0") { + assertEquals( + Vector2(-1, -1), + Hexagon.oddRowRotate(Vector2(-1, 0), Vector2(0, 0), 1) + ) + } + + test("should rotate (0, 1) 6 turns around 0, 0") { + assertEquals( + Vector2(0, 1), + Hexagon.oddRowRotate(Vector2(0, 1), Vector2(0, 0), 6) + ) + } + + test("should rotate (0, 1) 5 turns around 0, 0") { + assertEquals( + Vector2(1, 0), + Hexagon.oddRowRotate(Vector2(0, 1), Vector2(0, 0), 5) + ) + } + + test("should rotate (0, 1) 4 turns around 0, 0") { + assertEquals( + Vector2(0, -1), + Hexagon.oddRowRotate(Vector2(0, 1), Vector2(0, 0), 4) + ) + } + + test("should rotate (0, 1) 3 turns around 0, 0") { + assertEquals( + Vector2(-1, -1), + Hexagon.oddRowRotate(Vector2(0, 1), Vector2(0, 0), 3) + ) + } + + test("should rotate (0, 1) 2 turns around 0, 0") { + assertEquals( + Vector2(-1, 0), + Hexagon.oddRowRotate(Vector2(0, 1), Vector2(0, 0), 2) + ) + } + + test("should rotate (0, 1) 1 turn around 0, 0") { + assertEquals( + Vector2(-1, 1), + Hexagon.oddRowRotate(Vector2(0, 1), Vector2(0, 0), 1) + ) + } + + test("should rotate (0, 2) 1 turn around 0, 3") { + assertEquals( + Vector2(1, 2), + Hexagon.oddRowRotate(Vector2(0, 2), Vector2(0, 3), 1) + ) + } + + test("should rotate (0, 2) 3 turns around 0, 3") { + assertEquals( + Vector2(1, 4), + Hexagon.oddRowRotate(Vector2(0, 2), Vector2(0, 3), 3) + ) + } + + test("should rotate (-1, 6) 1 turn around 0, 6") { + assertEquals( + Vector2(-1, 5), + Hexagon.oddRowRotate(Vector2(-1, 6), Vector2(0, 6), 1) + ) + + } +} diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala index 249db306..e7caf6c4 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala @@ -2,6 +2,7 @@ package vgb.game.models import indigo.* import vgb.common.BoardOverlayType +import vgb.common.Hexagon import vgb.common.RoomType final case class BoardOverlay( @@ -17,7 +18,7 @@ final case class BoardOverlay( def rotate() = val rotatedOrigin = - Hexagon.evenRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) + Hexagon.oddRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) this.copy( origin = rotatedOrigin.toPoint, diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala index 707b39a9..4fc473ca 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala @@ -1,6 +1,7 @@ package vgb.game.models import indigo.* +import vgb.common.Hexagon trait Placeable: val rotation: TileRotation @@ -14,7 +15,7 @@ trait Placeable: def localToWorld(localPoint: Point) = val rotatedPoint = Hexagon - .evenRowRotate( + .oddRowRotate( Vector2.fromPoint(localPoint), Vector2.fromPoint(minPoint), rotation.toByte() diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala index 27e4670b..aa0d815e 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala @@ -1,6 +1,7 @@ package vgb.game.models import indigo.* +import vgb.common.Hexagon import vgb.common.RoomType final case class Room( @@ -14,7 +15,7 @@ final case class Room( def rotate() = val rotatedOrigin = - Hexagon.evenRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) + Hexagon.oddRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) this.copy( origin = rotatedOrigin.toPoint, rotation = rotation.nextRotation(false) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala index cfb624b7..728bbce3 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala @@ -52,3 +52,10 @@ object TileRotation: case "diagonal-right-reverse" => DiagonalRightReverse case _ => Default } + + def fromByte(i: Byte) = + TileRotation.values + // We can't discern vertical just from the byte, so don't try + .filter(t => t != Vertical && t != VerticalReverse) + .find(t => t.toByte() == i) + .getOrElse(Default) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala index f1b0b7b1..b78d05aa 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala @@ -2,7 +2,7 @@ package vgb.game.models.components import indigo.* import vgb.game.models.BoardOverlay -import vgb.game.models.Hexagon +import vgb.common.Hexagon import vgb.game.models.TileRotation import indigo.shared.scenegraph.Shape.Circle import vgb.game.models.LayerDepths @@ -13,19 +13,19 @@ import vgb.common.Flag object BoardOverlayComponent: def render(boardOverlay: BoardOverlay, cellMap: Map[Point, Int]): Layer = val offset = - Hexagon.evenRowToScreenPos(HexComponent.height, Point.zero) + + Hexagon.oddRowToScreenPos(HexComponent.height, Point.zero) + Point((HexComponent.width * 0.5).toInt, (HexComponent.height * 0.5).toInt) val origin = - Hexagon.evenRowToScreenPos(HexComponent.height, boardOverlay.origin) + Hexagon.oddRowToScreenPos(HexComponent.height, boardOverlay.origin) val rotationPoint = - Hexagon.evenRowToScreenPos(HexComponent.height, boardOverlay.rotationPoint) + Hexagon.oddRowToScreenPos(HexComponent.height, boardOverlay.rotationPoint) val newRotation = - Hexagon.evenRowToScreenPos( + Hexagon.oddRowToScreenPos( HexComponent.height, Hexagon - .evenRowRotate(Vector2.fromPoint(boardOverlay.origin), Vector2.fromPoint(boardOverlay.rotationPoint), 1) + .oddRowRotate(Vector2.fromPoint(boardOverlay.origin), Vector2.fromPoint(boardOverlay.rotationPoint), 1) .toPoint ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala index c37d5ac0..97e7d7ba 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala @@ -5,7 +5,7 @@ import indigo.shared.scenegraph.Shape.Line import indigo.shared.scenegraph.Shape.Polygon import indigo.shared.scenegraph.Shape.Circle import indigo.shared.datatypes.Fill.Color -import vgb.game.models.Hexagon +import vgb.common.Hexagon object HexComponent: val height = 90 @@ -32,7 +32,7 @@ object HexComponent: polygon .withFill(Fill.Color(fill)) // 0,0 position is the top left - .moveTo(Hexagon.evenRowToScreenPos(height, position)) + .moveTo(Hexagon.oddRowToScreenPos(height, position)) // For screen position to co-ordinates to work correctly, 0,0 needs to be centre .moveBy((polygon.size.width * -0.5).toInt, (polygon.size.height * -0.5).toInt) ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/MonsterComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/MonsterComponent.scala index 60694c75..ebf6ce08 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/MonsterComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/MonsterComponent.scala @@ -3,7 +3,7 @@ package vgb.game.models.components import indigo.* import indigo.shared.scenegraph.Shape.Box import vgb.common.MonsterType -import vgb.game.models.Hexagon +import vgb.common.Hexagon import vgb.game.models.ScenarioMonster import vgb.common.MonsterLevel import indigo.shared.datatypes.Rectangle @@ -20,7 +20,7 @@ object MonsterComponent: def render(monster: ScenarioMonster, cellMap: Map[Point, Int]): Layer = val origin = - Hexagon.evenRowToScreenPos(HexComponent.height, monster.initialPosition) + Hexagon.oddRowToScreenPos(HexComponent.height, monster.initialPosition) val quarterSize = Math.ceil(HexComponent.halfWidth * 0.5).toInt val playerMarker = Box( Rectangle( diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala index 11000e0e..fde58935 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala @@ -1,30 +1,30 @@ package vgb.game.models.components import indigo.* -import vgb.game.models.Room +import vgb.common.Hexagon import indigo.shared.scenegraph.Shape.Circle import indigo.shared.scenegraph.Shape.Box import org.scalajs.dom.PointerEvent import vgb.game.MoveStart -import vgb.game.models.Hexagon import vgb.game.models.LayerDepths +import vgb.game.models.Room object RoomComponent: def render(room: Room, camera: Camera, moveable: Boolean) = val offset = - Hexagon.evenRowToScreenPos(HexComponent.height, Point.zero) + + Hexagon.oddRowToScreenPos(HexComponent.height, Point.zero) + Point(HexComponent.width.toInt, (HexComponent.height * 0.5).toInt) - room.roomType.offset val origin = - Hexagon.evenRowToScreenPos(HexComponent.height, room.origin) + Hexagon.oddRowToScreenPos(HexComponent.height, room.origin) val rotationPoint = - Hexagon.evenRowToScreenPos(HexComponent.height, room.rotationPoint) + Hexagon.oddRowToScreenPos(HexComponent.height, room.rotationPoint) val newRotation = - Hexagon.evenRowToScreenPos( + Hexagon.oddRowToScreenPos( HexComponent.height, - Hexagon.evenRowRotate(Vector2.fromPoint(room.origin), Vector2.fromPoint(room.rotationPoint), 1).toPoint + Hexagon.oddRowRotate(Vector2.fromPoint(room.origin), Vector2.fromPoint(room.rotationPoint), 1).toPoint ) Layer( diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala index f3385b3e..dc7f8a76 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala @@ -53,3 +53,9 @@ object CreatorModel: Batch.empty, Batch.empty ) + + def fromJson(json: String): Either[String, CreatorModel] = + decode[CreatorStorage](json) match { + case Right(value) => value.toModel() + case Left(err) => Left(err.getMessage()) + } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala index f0d47b09..b5ef4185 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala @@ -1,6 +1,11 @@ package vgb.game.models.storage import vgb.game.models.sceneModels.CreatorModel +import vgb.common.BaseGame +import indigo.shared.collections.Batch +import vgb.game.models.Room +import vgb.game.models.ScenarioMonster +import vgb.game.models.BoardOverlay final case class CreatorStorage( scenarioTitle: String, @@ -8,13 +13,49 @@ final case class CreatorStorage( roomData: List[RoomStorage], overlays: List[OverlayStorage], monsters: List[ScenarioMonsterStorage] -) +) { + def toModel(): Either[String, CreatorModel] = + val baseGame = this.baseGame match { + case Some(value) => + BaseGame.values.find(g => g.toString().toLowerCase() == value) match { + case Some(bg) => bg + case None => BaseGame.Gloomhaven + } + case None => BaseGame.Gloomhaven + } + + val roomData = this.roomData.map(r => r.toModel(baseGame)) + val overlays = this.overlays.map(o => o.toModel(baseGame)) + val monsters = this.monsters.map(m => m.toModel(baseGame)) + + val errors = + roomData.collect { case Left(e) => e } ++ + overlays.collect { case Left(e) => e } ++ + monsters.collect { case Left(e) => e } + + errors.headOption match { + case Some(value) => Left(value) + case None => + Right( + CreatorModel( + scenarioTitle, + baseGame, + Batch.fromList(roomData.collect { case Right(r) => r }), + Batch.fromList(monsters.collect { case Right(m) => m }), + Batch.fromList(overlays.collect { case Right(o) => o }) + ) + ) + } +} object CreatorStorage: def fromModel(model: CreatorModel) = CreatorStorage( model.scenarioTitle, - Some(model.baseGame.toString()), + model.baseGame match { + case BaseGame.Gloomhaven => None + case _ => Some(model.baseGame.toString().toLowerCase()) + }, model.rooms.map(r => RoomStorage.fromModel(r)).toList, model.overlays.map(o => OverlayStorage.fromModel(o)).toList, model.monsters.map(m => ScenarioMonsterStorage.fromModel(m)).toList diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala index 83dfa6e3..76463051 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala @@ -1,16 +1,204 @@ package vgb.game.models.storage +import indigo.* + import vgb.common.* import vgb.game.models.BoardOverlay import indigo.shared.collections.Batch import indigo.shared.datatypes.RGB +import vgb.game.models.TileRotation +import indigo.shared.datatypes.Point final case class OverlayStorage( ref: OverlayStorageRef, id: Int, direction: String, cells: List[List[Int]] -) +) { + def toModel(baseGame: BaseGame): Either[String, BoardOverlay] = + decodeOverlay(baseGame).map { overlay => + val minCell = cells + .foldLeft(Option.empty[Point])((p, c) => + val cp = Point( + c.lift(0).getOrElse(0), + c.lift(1).getOrElse(0) + ) + + p.map(cp.min).orElse(Some(cp)) + ) + .getOrElse(Point.zero) + + val minPoint = overlay.worldCells + .foldLeft(Option.empty[Point])((p, c) => p.map(c.min).orElse(Some(c))) + .getOrElse(Point.zero) + + val o = overlay.copy(origin = minCell - minPoint) + IndigoLogger.consoleLog(o.worldCells.toString()) + o + } + + private def decodeOverlay(baseGame: BaseGame) = + (ref.`type`.toLowerCase(), ref.subType.map(st => st.toLowerCase())) match { + case ("door", Some("corridor")) => decodeCorridor(baseGame) + case ("difficult-terrain", _) => + decodeFromSubtype( + baseGame, + DifficultTerrain.values.asInstanceOf[Array[BoardOverlayType]] + ) + case ("door", _) => decodeDoor(baseGame) + case ("hazard", _) => + decodeFromSubtype( + baseGame, + Hazard.values.asInstanceOf[Array[BoardOverlayType]] + ) + case ("highlight", _) => decodeHighlight(baseGame) + case ("obstacle", _) => + decodeFromSubtype( + baseGame, + Obstacle.values.asInstanceOf[Array[BoardOverlayType]] + ) + case ("rift", _) => decodeRift(baseGame) + case ("starting-location", _) => decodeStartingLocation(baseGame) + case ("trap", _) => + decodeFromSubtype( + baseGame, + Trap.values.asInstanceOf[Array[BoardOverlayType]] + ) + case ("treasure", Some("chest")) => decodeTreasureChest(baseGame) + case ("treasure", Some("coin")) => decodeTreasureCoin(baseGame) + case ("token", _) => decodeToken(baseGame) + case ("wall", _) => + decodeFromSubtype( + baseGame, + Wall.values.asInstanceOf[Array[BoardOverlayType]] + ) + case _ => Left(s"""Overlay type ${ref.`type`} does not exist for ${baseGame}""") + } + // TODO: We need to move the overlay once it's been created + + private def decodeCorridor(baseGame: BaseGame) = + ref.material match { + case Some(material) => + val overlayType = Corridor.values.find(c => c.baseGame == baseGame && c.codedName == material) + overlayType match { + case Some(o) => + Right( + BoardOverlay(id, o, Point.zero, TileRotation.fromString(direction)) + ) + case None => Left(s"""Could not find corridor ${ref.material} for ${baseGame}""") + } + case None => Left("Material is missing for corridor") + } + + private def decodeFromSubtype(baseGame: BaseGame, values: Array[BoardOverlayType]) = + ref.subType match { + case Some(subType) => + val overlayType = values.find(c => c.baseGame == baseGame && c.codedName == subType) + overlayType match { + case Some(o) => + Right( + BoardOverlay(id, o, Point.zero, TileRotation.fromString(direction)) + ) + case None => Left(s"""Could not find ${ref.`type`} ${ref.subType} for ${baseGame}""") + } + case None => Left(s"""SubType is missing for ${ref.`type`}""") + } + + private def decodeDoor(baseGame: BaseGame) = + ref.subType match { + case Some(subType) => + val links = ref.links.getOrElse(List.empty) + val overlayType = Door.values.find(c => c.baseGame == baseGame && c.codedName == subType) + overlayType match { + case Some(o) => + Right( + BoardOverlay( + id, + o, + Point.zero, + TileRotation.fromString(direction), + Some( + Batch.fromArray( + RoomType.values + .filter(r => + r.baseGame == baseGame && + links.exists(l => l == r.mapRef) + ) + ) + ) + ) + ) + case None => Left(s"""Could not find door ${ref.subType} for ${baseGame}""") + } + case None => Left(s"""SubType is missing for door""") + } + + private def decodeHighlight(baseGame: BaseGame) = + ref.colour match { + case Some(colour) => + Right( + BoardOverlay( + id, + Highlight(baseGame, RGB.fromHexString(colour)), + Point.zero, + TileRotation.fromString(direction) + ) + ) + case None => Left("Colour is missing for highlight") + } + + private def decodeRift(baseGame: BaseGame) = + Right(BoardOverlay(id, Rift(baseGame), Point.zero, TileRotation.fromString(direction))) + + private def decodeStartingLocation(baseGame: BaseGame) = + StartingLocation.values.find(s => s.baseGame == baseGame) match { + case Some(startingLocation) => + Right(BoardOverlay(id, startingLocation, Point.zero, TileRotation.fromString(direction))) + case None => Left(s"""Cannot find starting location for ${baseGame}""") + } + + def decodeTreasureChest(baseGame: BaseGame) = + ref.id match { + case Some(i) => + Right( + BoardOverlay( + id, + Treasure.Chest(baseGame, TreasureChestType.fromString(i)), + Point.zero, + TileRotation.fromString(direction) + ) + ) + case None => Left("Id not found for treasure chest") + } + + def decodeTreasureCoin(baseGame: BaseGame) = + ref.amount match { + case Some(amount) => + Right( + BoardOverlay( + id, + Treasure.Coin(baseGame, amount), + Point.zero, + TileRotation.fromString(direction) + ) + ) + case None => Left("Amount not found for coin") + } + + def decodeToken(baseGame: BaseGame) = + ref.value match { + case Some(c) => + Right( + BoardOverlay( + id, + Token(baseGame, c), + Point.zero, + TileRotation.fromString(direction) + ) + ) + case None => Left("Value not found for token") + } +} final case class OverlayStorageRef( `type`: String, @@ -39,30 +227,30 @@ object OverlayStorage: OverlayStorageRef( "door", "corridor", - c.name, + c.codedName, c.cells.length.toByte, - overlay.linkedRooms.getOrElse(Batch.empty).toList.map(r => r.toString()) + overlay.linkedRooms.getOrElse(Batch.empty).toList.map(r => r.mapRef) ) - case o: DifficultTerrain => OverlayStorageRef("difficult-terrain", o.name) + case o: DifficultTerrain => OverlayStorageRef("difficult-terrain", o.codedName) case d: Door => OverlayStorageRef( "door", - d.name, + d.codedName, overlay.linkedRooms.getOrElse(Batch.empty).toList.map(r => r.toString()) ) - case h: Hazard => OverlayStorageRef("hazard", h.name) + case h: Hazard => OverlayStorageRef("hazard", h.codedName) case h: Highlight => OverlayStorageRef("highlight", h.colour) - case o: Obstacle => OverlayStorageRef("obstacle", o.name) + case o: Obstacle => OverlayStorageRef("obstacle", o.codedName) case r: Rift => OverlayStorageRef("rift") case s: StartingLocation => OverlayStorageRef("starting-location") - case t: Trap => OverlayStorageRef("trap", t.name) + case t: Trap => OverlayStorageRef("trap", t.codedName) case t: Treasure => t match { case t: Treasure.Chest => OverlayStorageRef("treasure", "chest", t.treasureType) case t: Treasure.Coin => OverlayStorageRef("treasure", "coin", t.amount) } case Token(_, value) => OverlayStorageRef("token", value) - case w: Wall => OverlayStorageRef("wall", w.name) + case w: Wall => OverlayStorageRef("wall", w.codedName) } object OverlayStorageRef: @@ -82,7 +270,7 @@ object OverlayStorageRef: def apply(overlayType: String, subType: String): OverlayStorageRef = OverlayStorageRef( overlayType, - Some(subType.toLowerCase().replace(" ", "-")), + Some(subType), None, None, None, @@ -121,7 +309,7 @@ object OverlayStorageRef: def apply(overlayType: String, subType: String, mapRefs: List[String]): OverlayStorageRef = OverlayStorageRef( overlayType, - Some(subType.toLowerCase().replace(" ", "-")), + Some(subType), None, None, Some(mapRefs), @@ -134,7 +322,7 @@ object OverlayStorageRef: def apply(overlayType: String, subType: String, amount: Byte): OverlayStorageRef = OverlayStorageRef( overlayType, - Some(subType.toLowerCase().replace(" ", "-")), + Some(subType), None, None, None, @@ -147,17 +335,13 @@ object OverlayStorageRef: def apply(overlayType: String, subType: String, treasureType: TreasureChestType): OverlayStorageRef = OverlayStorageRef( overlayType, - Some(subType.toLowerCase().replace(" ", "-")), + Some(subType), None, None, None, None, None, - Some(treasureType match { - case TreasureChestType.Goal => "goal" - case TreasureChestType.Locked => "locked" - case TreasureChestType.Normal(i) => i.toString() - }), + Some(treasureType.toString()), None ) @@ -170,8 +354,8 @@ object OverlayStorageRef: ): OverlayStorageRef = OverlayStorageRef( overlayType, - Some(subType.toLowerCase().replace(" ", "-")), - Some(material.toLowerCase().replace(" ", "-")), + Some(subType), + Some(material), Some(size), Some(mapRefs), None, diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala index 28e12b0e..107bc82f 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala @@ -1,16 +1,34 @@ package vgb.game.models.storage +import indigo.* + import vgb.game.models.Room +import vgb.common.BaseGame +import vgb.common.RoomType +import indigo.shared.datatypes.Point +import vgb.game.models.TileRotation final case class RoomStorage( data: RoomDataStorage, rotationPoint: CellStorage -) +) { + def toModel(baseGame: BaseGame): Either[String, Room] = + val roomType = RoomType.values + .find(r => r.baseGame == baseGame && r.mapRef.toLowerCase() == data.ref.toLowerCase()) + roomType match { + case Some(roomType) => + Right( + Room(roomType, Point(data.origin.x, data.origin.y), TileRotation.fromByte(data.turns)) + ) + case None => Left(s"""Map tile ${data.ref} does not exist for ${baseGame}""") + + } +} final case class RoomDataStorage( ref: String, origin: CellStorage, - turns: Int + turns: Byte ) object RoomStorage: diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala index dee9e475..5246f862 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala @@ -1,6 +1,10 @@ package vgb.game.models.storage +import indigo.shared.datatypes.Point import vgb.game.models.ScenarioMonster +import vgb.common.MonsterLevel +import vgb.common.MonsterType +import vgb.common.BaseGame final case class ScenarioMonsterStorage( monster: String, @@ -9,7 +13,27 @@ final case class ScenarioMonsterStorage( twoPlayer: String, threePlayer: String, fourPlayer: String -) +) { + def toModel(baseGame: BaseGame): Either[String, ScenarioMonster] = + val monsterType = MonsterType.values.find(m => + m.baseGame == baseGame && + m.assetName.toString().toLowerCase() == monster.toLowerCase() + ) + + monsterType match { + case Some(monsterType) => + Right( + ScenarioMonster( + monsterType, + Point(initialX, initialY), + MonsterLevel.fromString(twoPlayer), + MonsterLevel.fromString(threePlayer), + MonsterLevel.fromString(fourPlayer) + ) + ) + case None => Left(s"""Monster ${monster} does not exist for ${baseGame}""") + } +} object ScenarioMonsterStorage: def fromModel(monster: ScenarioMonster) = diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala index ed8035cd..2bd3947b 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -11,7 +11,7 @@ import vgb.game.models.GameModel import vgb.game.models.GameViewModel import vgb.game.MoveStart import vgb.game.MoveEnd -import vgb.game.models.Hexagon +import vgb.common.Hexagon import vgb.game.models.ScenarioMonster import vgb.game.models.TileRotation import vgb.game.models.components.* @@ -69,7 +69,29 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg tyrianSubSystem.TyrianEvent .Send(CreatorMsgType.UpdateDragMenu(DragMenuComponent.getForModel(model))) ) + .addGlobalEvents(StorageEvent.Load(saveSlot)) else Outcome(model) + case StorageEvent.Loaded(key, data) => + data match { + case Some(d) => + CreatorModel.fromJson(d) match { + case Right(m) => + Outcome(m) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent + .Send(CreatorMsgType.UpdateDragMenu(DragMenuComponent.getForModel(m))) + ) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent + .Send(CreatorMsgType.ChangeScenarioTitle(m.scenarioTitle)) + ) + case Left(e) => + IndigoLogger.consoleLog(e) + Outcome(model) + } + case None => Outcome(model) + } + case MoveEnd(newPos, d) => val newModel = d match { @@ -127,7 +149,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg ( viewModel.dragging match { case None => - val pos = Hexagon.screenPosToEvenRow(HexComponent.height, p + viewModel.camera.position).toPoint + val pos = Hexagon.screenPosToOddRow(HexComponent.height, p + viewModel.camera.position).toPoint val data = model.monsters.find(m => m.initialPosition == pos) match { case Some(v) => Some(v) case None => model.overlays.find(o => o.worldCells.contains(pos)) @@ -144,7 +166,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg .Send(GeneralMsgType.CloseContextMenu) ) case MouseEvent.Move(p) => - val pos = Hexagon.screenPosToEvenRow(HexComponent.height, p + viewModel.camera.position).toPoint + val pos = Hexagon.screenPosToOddRow(HexComponent.height, p + viewModel.camera.position).toPoint val draggingData = viewModel.dragging.orElse( viewModel.initialDragger match { @@ -191,7 +213,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg case Some(d) if d.hasMoved => Outcome(viewModel.copy(dragging = None)) case _ => - val hexPos = Hexagon.screenPosToEvenRow(HexComponent.height, p + viewModel.camera.position).toPoint + val hexPos = Hexagon.screenPosToOddRow(HexComponent.height, p + viewModel.camera.position).toPoint Outcome(viewModel.copy(dragging = None)) .addGlobalEvents( tyrianSubSystem.TyrianEvent @@ -280,6 +302,31 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg case _ => Layer() } ) + .addLayer( + Layer( + Batch + .fromArray( + (0 until 10).toArray + .map(x => + (0 until 10).toArray + .map(y => + HexComponent.render( + Point(x, y), + cellMap.get(Point(x, y)) match { + case Some(flags) => + if (flags & Flag.Monster.value) != 0 then RGBA(1, 0, 0, 0.5) + else if (flags & Flag.Obstacle.value) != 0 then RGBA(0, 0, 1, 0.5) + else if (flags & Flag.Room.value) != 0 then RGBA(0, 1, 0, 0.5) + else RGBA.Zero + case None => RGBA.Zero + } + ) + ) + ) + .flatten + ) + ) + ) .withCamera(viewModel.camera) ) @@ -326,7 +373,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg model.rooms.find(r1 => r1.roomType == r) match { case Some(room) => val rotatedOrigin = - Hexagon.evenRowRotate(Vector2.fromPoint(room.origin), Vector2.fromPoint(room.rotationPoint), 1) + Hexagon.oddRowRotate(Vector2.fromPoint(room.origin), Vector2.fromPoint(room.rotationPoint), 1) val newRoom = room.copy( origin = rotatedOrigin.toPoint, rotation = room.rotation.nextRotation(false) diff --git a/ci.sh b/ci.sh old mode 100644 new mode 100755 index 808cfddd..741b4d51 --- a/ci.sh +++ b/ci.sh @@ -2,14 +2,22 @@ set -e -cd ui - -mill clean ui -mill ui.compile -mill ui.checkFormat -mill ui.fix -mill ui.fastLinkJS -mill ui.test +cd VirtualGloomhavenBoard/Indigo + +mill clean vgb-common +mill vgb-common.compile +mill vgb-common.fastLinkJS +mill vgb-common.test + +mill clean vgb-game +mill vgb-game.compile +mill vgb-game.fastLinkJS +mill vgb-game.test + +mill clean vgb-ui +mill vgb-ui.compile +mill vgb-ui.fastLinkJS +mill vgb-ui.test cd .. From bdb90a86526ef66188060bf12a69a784a5b5622f Mon Sep 17 00:00:00 2001 From: David North Date: Mon, 10 Jul 2023 08:18:44 +0100 Subject: [PATCH 56/60] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4b374441..cf7b88e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,6 @@ jobs: java-version: adopt@1.11 - uses: jodersky/setup-mill@master with: - mill-version: 0.10.12 + mill-version: 0.11.1 - name: Compile & Test run: bash ci.sh From f949f453fcad232cc12674ba06cd5dcba2becf62 Mon Sep 17 00:00:00 2001 From: David North Date: Wed, 12 Jul 2023 07:48:54 +0100 Subject: [PATCH 57/60] Finishes conversion to odd row --- .../vgb-common/src/vgb/common/RoomType.scala | 2 +- .../test/src/vgb/common/HexagonTests.scala | 13 +++++++++++++ .../src/vgb/game/models/BoardOverlay.scala | 3 +++ .../vgb-game/src/vgb/game/models/GameRules.scala | 3 ++- .../vgb-game/src/vgb/game/models/Placeable.scala | 16 +++++++++------- .../game/models/components/HexComponent.scala | 6 ++++-- .../game/models/components/RoomComponent.scala | 2 +- 7 files changed, 33 insertions(+), 12 deletions(-) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala index b85eea06..40d3adba 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala @@ -9,7 +9,7 @@ enum RoomType(val baseGame: BaseGame, val mapRef: String, val offset: Point, val extends RoomType( BaseGame.Gloomhaven, "a1a", - Point(-13, -34), + Point(27, 33), Batch( Point(0, 1), Point(1, 1), diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala index ac5eb659..6836f8bd 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala @@ -86,6 +86,19 @@ class HexagonTests extends munit.FunSuite { Vector2(-1, 5), Hexagon.oddRowRotate(Vector2(-1, 6), Vector2(0, 6), 1) ) + } + test("should rotate (1, 1) 1 turns around 0, 1") { + assertEquals( + Vector2(1, 2), + Hexagon.oddRowRotate(Vector2(1, 1), Vector2(0, 1), 1) + ) + } + + test("should rotate (1, 1) 2 turns around 0, 1") { + assertEquals( + Vector2(0, 2), + Hexagon.oddRowRotate(Vector2(1, 1), Vector2(0, 1), 2) + ) } } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala index e7caf6c4..a1b8f2b9 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala @@ -17,9 +17,12 @@ final case class BoardOverlay( val worldCells = overlayType.cells.map(localToWorld) def rotate() = + IndigoLogger.consoleLog(Vector2.fromPoint(rotationPoint).toString()) + val rotatedOrigin = Hexagon.oddRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) + IndigoLogger.consoleLog(rotatedOrigin.toString()) this.copy( origin = rotatedOrigin.toPoint, rotation = rotation.nextRotation(overlayType.verticalAssetName != None) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala index 61a3dfcb..1f1d1d3a 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala @@ -78,7 +78,8 @@ object GameRules: cellMap: Map[Point, Int] ): BoardOverlay = val rotatedOverlay = overlay.rotate() - if rotatedOverlay.overlayType.flag == Flag.Coin || initialRotation == rotatedOverlay.rotation then rotatedOverlay + if rotatedOverlay.overlayType.flag == Flag.Coin || initialRotation == rotatedOverlay.rotation then + rotatedOverlay else if canPlaceOverlay(rotatedOverlay, cellMap) then rotatedOverlay else nextValidOverlayRotation(initialRotation, rotatedOverlay, cellMap) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala index 4fc473ca..7da6c629 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala @@ -14,14 +14,16 @@ trait Placeable: ) def localToWorld(localPoint: Point) = - val rotatedPoint = Hexagon + val worldPoint = localPoint + origin + val offset = Point( + if (localPoint.y & 1) == 1 && (worldPoint.y & 1) == 0 then 1 + else 0, + 0 + ) + Hexagon .oddRowRotate( - Vector2.fromPoint(localPoint), - Vector2.fromPoint(minPoint), + Vector2.fromPoint(worldPoint + offset), + Vector2.fromPoint(origin), rotation.toByte() ) .toPoint - - rotatedPoint - + origin - + (if (origin.y & 1) == 1 && (rotatedPoint.y & 1) == 1 then Point(-1, 0) else Point.zero) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala index 97e7d7ba..b0ce262c 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala @@ -21,7 +21,8 @@ object HexComponent: Point(Math.floor(halfWidth).toInt, Math.ceil(quarterSize).toInt), // Right-bottom corner of rectangle Point(0, Math.ceil(halfSize).toInt), // Bottom tip Point(-Math.ceil(halfWidth).toInt, Math.ceil(quarterSize).toInt), // Left-bottom corner of rectangle, - Point(-Math.ceil(halfWidth).toInt, -Math.floor(quarterSize).toInt) // Left-top corner of rectangle + Point(-Math.ceil(halfWidth).toInt, -Math.floor(quarterSize).toInt), // Left-top corner of rectangle + Point(0, -Math.floor(halfSize).toInt) // Top tip ), Fill.Color(RGBA.None), Stroke.Black @@ -34,5 +35,6 @@ object HexComponent: // 0,0 position is the top left .moveTo(Hexagon.oddRowToScreenPos(height, position)) // For screen position to co-ordinates to work correctly, 0,0 needs to be centre - .moveBy((polygon.size.width * -0.5).toInt, (polygon.size.height * -0.5).toInt) + .moveBy((polygon.size.width * -0.5).toInt, (polygon.size.height * -0.5).toInt), + Circle(Point(0, 0), 2, Fill.Color(RGBA.Red)).moveTo(Hexagon.oddRowToScreenPos(height, position)) ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala index fde58935..f9f4a640 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala @@ -37,7 +37,7 @@ object RoomComponent: (if moveable then Batch( Graphic(Size(45, 45), Material.Bitmap(AssetName("move-icon"))) - .moveTo(origin) + .moveTo(origin - room.localToWorld(room.minPoint)) .moveBy(Point(-(HexComponent.width * 0.5).toInt - 22, -(HexComponent.height * 0.5).toInt - 28)) .enableEvents .withEventHandler((g, e) => From 5d4341a456dba9b9da9786519a92db57d8d6370e Mon Sep 17 00:00:00 2001 From: David North Date: Thu, 10 Aug 2023 08:30:28 +0100 Subject: [PATCH 58/60] Starts adding import/export to creator --- VirtualGloomhavenBoard/Indigo/.jvmopts | 1 + VirtualGloomhavenBoard/Indigo/build.sc | 4 +- .../vgb-common/src/vgb/common/CommonMsg.scala | 7 +- .../vgb-common/src/vgb/common/Hexagon.scala | 2 - .../vgb-common/src/vgb/common/RoomType.scala | 18 ++ .../Indigo/vgb-game/src/vgb/game/Main.scala | 5 +- .../src/vgb/game/models/Placeable.scala | 42 ++- .../components/BoardOverlayComponent.scala | 4 +- .../models/components/DragMenuComponent.scala | 19 +- .../models/components/RoomComponent.scala | 4 +- .../vgb/game/models/storage/DoorStorage.scala | 79 ++++++ .../models/storage/MapTileDataStorage.scala | 64 +++++ .../game/models/storage/ScenarioStorage.scala | 252 ++++++++++++++++++ .../src/vgb/game/scenes/CreatorScene.scala | 30 ++- .../src/vgb/game/models/PlaceableTests.scala | 80 ++++++ .../src/vgb/ui/scenes/CreatorScene.scala | 9 +- .../static/img/map-tiles/gloomhaven/a1b.webp | Bin 0 -> 6982 bytes .../static/img/overlays/door-altar.webp | Bin 0 -> 2312 bytes 18 files changed, 591 insertions(+), 29 deletions(-) create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala create mode 100644 VirtualGloomhavenBoard/Indigo/vgb-game/test/src/vgb/game/models/PlaceableTests.scala create mode 100644 VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1b.webp create mode 100644 VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/door-altar.webp diff --git a/VirtualGloomhavenBoard/Indigo/.jvmopts b/VirtualGloomhavenBoard/Indigo/.jvmopts index 3457f79c..58808e04 100644 --- a/VirtualGloomhavenBoard/Indigo/.jvmopts +++ b/VirtualGloomhavenBoard/Indigo/.jvmopts @@ -2,3 +2,4 @@ -Xms1G -Xmx8G -XX:+UseG1GC +-Xmax-inlines:64 diff --git a/VirtualGloomhavenBoard/Indigo/build.sc b/VirtualGloomhavenBoard/Indigo/build.sc index b4ce5ab7..0b1b5ba8 100644 --- a/VirtualGloomhavenBoard/Indigo/build.sc +++ b/VirtualGloomhavenBoard/Indigo/build.sc @@ -55,8 +55,8 @@ trait VgbModule extends ScalaJSModule { def scalaVersion = "3.3.0" def scalaJSVersion = "1.13.1" - val indigoVersion = "0.15.0-RC2" - val tyrianVersion = "0.7.1" + val indigoVersion = "0.15.0-RC4" + val tyrianVersion = "0.7.2-SNAPSHOT" val circeVersion = "0.14.1" def ivyDeps = diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala index 05951673..ed79094a 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala @@ -3,6 +3,8 @@ package vgb.common import indigo.Point import indigo.shared.collections.Batch +import org.scalajs.dom + /** A message from the VGB app */ trait GloomhavenMsg @@ -22,9 +24,12 @@ enum CreatorMsgType extends GloomhavenMsg: case RemoveRoom(r: RoomType) case CreateNewScenario case ShowImportDialog - case ShowExportDialog + case ImportFileSelected(file: dom.File) case ChangeScenarioTitle(title: String) case UpdateDragMenu(sections: Batch[DragDropSection]) case SetSelectedDragSection(sectionName: String) case NewDragStart(dragItem: RoomType | BoardOverlayType | MonsterType) case DragEnd + case SelectFile + case ExportFile + case ExportFileString(title: String, json: String) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala index b506ae5f..8c954e9e 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala @@ -79,8 +79,6 @@ object Hexagon: numTurns match case 0 => origin case 1 => rotateResult - case other if other < 0 => - oddRowRotate(rotateResult, rotationPoint, (other + 1).toByte) case other => oddRowRotate(rotateResult, rotationPoint, (other - 1).toByte) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala index 40d3adba..362e11d1 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala @@ -23,6 +23,24 @@ enum RoomType(val baseGame: BaseGame, val mapRef: String, val offset: Point, val ), Size(432, 244) ) + case RoomA1B + extends RoomType( + BaseGame.Gloomhaven, + "a1b", + Point(27, 33), + Batch( + Point(0, 1), + Point(1, 1), + Point(2, 1), + Point(3, 1), + Point(0, 2), + Point(1, 2), + Point(2, 2), + Point(3, 2), + Point(4, 2) + ), + Size(432, 244) + ) /* { diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala index 5fb2f64d..7e8212a2 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala @@ -43,15 +43,18 @@ final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) GameConfig.default .withMagnification(magnification) .withTransparentBackground(true) - .withViewport(gameViewport), + .withViewport(gameViewport) + .withResizePolicy(ResizePolicy.NoResize), gameViewport.size / magnification ) .withSubSystems(tyrianSubSystem) .withAssets( AssetType.Image(AssetName("gh-a1a"), AssetPath("img/map-tiles/gloomhaven/a1a.webp")), + AssetType.Image(AssetName("gh-a1b"), AssetPath("img/map-tiles/gloomhaven/a1a.webp")), AssetType.Image(AssetName("aesther-ashblade"), AssetPath("img/monsters/aesther-ashblade.webp")), AssetType.Image(AssetName("gh-boulder-2"), AssetPath("img/overlays/obstacle-boulder-2.webp")), AssetType.Image(AssetName("gh-coin"), AssetPath("img/overlays/treasure-coin.webp")), + AssetType.Image(AssetName("gh-altar"), AssetPath("img/overlays/door-altar.webp")), AssetType.Image(AssetName("move-icon"), AssetPath("img/move-icon.webp")), AssetType.Image(AssetName("hex-border"), AssetPath("img/hex-border.webp")), AssetType.Font(AssetName("PirateOne"), AssetPath("fonts/PirataOne-Gloomhaven.woff2")) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala index 7da6c629..1d443da8 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala @@ -20,10 +20,40 @@ trait Placeable: else 0, 0 ) - Hexagon - .oddRowRotate( - Vector2.fromPoint(worldPoint + offset), - Vector2.fromPoint(origin), - rotation.toByte() + + if rotation.toByte() == 0 then worldPoint + offset + else + Hexagon + .oddRowRotate( + Vector2.fromPoint(worldPoint + offset), + Vector2.fromPoint(origin), + rotation.toByte() + ) + .toPoint + + def worldToLocal(worldPoint: Point) = + if rotation.toByte() == 0 then + val localPoint = worldPoint - origin + val offset = Point( + if (localPoint.y & 1) == 1 && (worldPoint.y & 1) == 0 then 1 + else 0, + 0 ) - .toPoint + localPoint - offset + else + var rotatedPoint = Hexagon + .oddRowRotate( + Vector2.fromPoint(worldPoint), + Vector2.fromPoint(origin), + (6 - rotation.toByte().toInt).toByte + ) + .toPoint + + var localPoint = rotatedPoint - origin + val offset = Point( + if (localPoint.y & 1) == 1 && (rotatedPoint.y & 1) == 0 then 1 + else 0, + 0 + ) + + localPoint - offset diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala index b78d05aa..0e32c108 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala @@ -7,6 +7,7 @@ import vgb.game.models.TileRotation import indigo.shared.scenegraph.Shape.Circle import vgb.game.models.LayerDepths import vgb.common.Treasure +import vgb.common.Door import vgb.common.Token import vgb.common.Flag @@ -58,7 +59,8 @@ object BoardOverlayComponent: val graphicGroup = Graphic( boardOverlay.overlayType match { - case t: Treasure.Coin => Size(90, 90) + case _: Treasure.Coin => Size(90, 90) + case _: Door => Size(79, 90) case _ => Size(156, 90) }, Material.Bitmap( diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala index ffe5d891..99b2ec0c 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala @@ -4,6 +4,7 @@ import vgb.game.models.sceneModels.CreatorModel import vgb.common.DragDropSection import vgb.common.DragDropItem import vgb.common.RoomType +import vgb.common.Door import vgb.common.Obstacle import vgb.common.Treasure import vgb.common.BaseGame @@ -11,15 +12,27 @@ import vgb.common.MonsterType import indigo.shared.collections.Batch object DragMenuComponent: - def getForModel(mode: CreatorModel) = + def getForModel(model: CreatorModel) = + val currentRooms = model.rooms.map(r => r.roomType) Batch( DragDropSection( "Tiles", Batch( - DragDropItem(RoomType.RoomA1A, false) + DragDropItem(RoomType.RoomA1A, false), + DragDropItem(RoomType.RoomA1B, false) + ).filter(i => + i.item match { + case r: RoomType => currentRooms.contains(r) == false + case _ => false + } + ) + ), + DragDropSection( + "Doors", + Batch( + DragDropItem(Door.Altar, false) ) ), - DragDropSection("Doors", Batch.empty), DragDropSection( "Obstacles", Batch( diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala index f9f4a640..d96566da 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala @@ -4,10 +4,10 @@ import indigo.* import vgb.common.Hexagon import indigo.shared.scenegraph.Shape.Circle import indigo.shared.scenegraph.Shape.Box -import org.scalajs.dom.PointerEvent import vgb.game.MoveStart import vgb.game.models.LayerDepths import vgb.game.models.Room +import indigo.shared.events.PointerEvent object RoomComponent: def render(room: Room, camera: Camera, moveable: Boolean) = @@ -42,7 +42,7 @@ object RoomComponent: .enableEvents .withEventHandler((g, e) => e match { - case MouseEvent.MouseDown(p, _) if g.bounds.contains(p + camera.position) => + case e: PointerEvent.PointerDown if g.bounds.contains(e.position + camera.position) => Some(MoveStart(room.origin, room)) case _ => None } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala new file mode 100644 index 00000000..c27fe364 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala @@ -0,0 +1,79 @@ +package vgb.game.models.storage + +import vgb.game.models.Room +import indigo.shared.collections.Batch +import vgb.common.RoomType +import vgb.game.models.BoardOverlay +import vgb.game.models.ScenarioMonster +import vgb.common.Door +import vgb.common.Corridor + +final case class DoorStorage( + subType: String, + material: Option[String], + size: Option[Byte], + direction: String, + room1X: Int, + room1Y: Int, + room2X: Int, + room2Y: Int, + mapTileData: MapTileDataStorage +) + +object DoorStorage: + def fromRooms( + room: Room, + overlays: Batch[(RoomType, BoardOverlay)], + monsters: Batch[(RoomType, ScenarioMonster)], + allRooms: Batch[Room], + remainingRooms: Batch[Room] + ): (Batch[DoorStorage], Batch[Room]) = + val (doorsForRoom, remainingOverlays) = overlays + .map(o => + if o._1 == room.roomType then + o._2.overlayType match { + case _: Door | _: Corridor => o._2 + case _ => o + } + else o + ) + .foldLeft((Batch.empty[BoardOverlay], Batch.empty[(RoomType, BoardOverlay)]))((cols, o) => + o match { + case o: BoardOverlay => (cols._1 :+ o, cols._2) + case o: (RoomType, BoardOverlay) => (cols._1, cols._2 :+ o) + } + ) + + doorsForRoom + .flatMap(d => + d.linkedRooms match { + case Some(links) => + Batch.fromArray( + links.toArray.flatMap(l => allRooms.find(r => r.roomType == l).map(r => (d, r))) + ) + case None => Batch.empty + } + ) + .foldLeft((Batch.empty[DoorStorage], remainingRooms))((data, link) => + (data, link) match { + case ((doorBatch, roomsLeft), (overlay, roomRef)) => + val overlayStorage = OverlayStorage.fromModel(overlay) + val roomPos = roomRef.worldToLocal(room.localToWorld(overlay.origin)) + val (mapTile, remainingRooms) = + MapTileDataStorage(roomRef, remainingOverlays, monsters, allRooms, roomsLeft.filter(r => r != roomRef)) + ( + doorBatch :+ DoorStorage( + overlayStorage.ref.subType.getOrElse(""), + overlayStorage.ref.material, + overlayStorage.ref.size, + overlayStorage.direction, + overlay.origin.x, + overlay.origin.y, + roomPos.x, + roomPos.y, + mapTile + ), + remainingRooms + ) + } + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala new file mode 100644 index 00000000..6ceb437f --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala @@ -0,0 +1,64 @@ +package vgb.game.models.storage + +import vgb.game.models.Room +import indigo.shared.collections.Batch +import vgb.common.RoomType +import vgb.game.models.BoardOverlay +import vgb.game.models.ScenarioMonster + +final case class MapTileDataStorage( + ref: String, + doors: List[DoorStorage], + overlays: List[OverlayStorage], + monsters: List[ScenarioMonsterStorage], + turns: Byte +) + +object MapTileDataStorage: + def apply( + room: Room, + overlays: Batch[(RoomType, BoardOverlay)], + monsters: Batch[(RoomType, ScenarioMonster)], + allRooms: Batch[Room], + remainingRooms: Batch[Room] + ): (MapTileDataStorage, Batch[Room]) = + val roomNeedsOutput = remainingRooms.contains(room) + val (roomOverlays, remainingOverlays) = + if roomNeedsOutput then + overlays + .map(o => if o._1 == room.roomType then o._2 else o) + .foldLeft((Batch.empty[OverlayStorage], Batch.empty[(RoomType, BoardOverlay)]))((cols, o) => + o match { + case o: BoardOverlay => (cols._1 :+ OverlayStorage.fromModel(o), cols._2) + case o: (RoomType, BoardOverlay) => (cols._1, cols._2 :+ o) + } + ) + else (Batch.empty, overlays) + + val (roomMonsters, remainingMonsters) = + if roomNeedsOutput then + monsters + .map(o => if o._1 == room.roomType then o._2 else o) + .foldLeft((Batch.empty[ScenarioMonsterStorage], Batch.empty[(RoomType, ScenarioMonster)]))((cols, o) => + o match { + case o: ScenarioMonster => (cols._1 :+ ScenarioMonsterStorage.fromModel(o), cols._2) + case o: (RoomType, ScenarioMonster) => (cols._1, cols._2 :+ o) + } + ) + else (Batch.empty, monsters) + + val (doors, newRemainingRooms) = + if roomNeedsOutput then + DoorStorage.fromRooms(room, remainingOverlays, remainingMonsters, allRooms, remainingRooms) + else (Batch.empty, remainingRooms) + + ( + MapTileDataStorage( + room.roomType.mapRef, + doors.toList, + roomOverlays.toList, + roomMonsters.toList, + room.rotation.toByte() + ), + newRemainingRooms.filter(r => r != room) + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala new file mode 100644 index 00000000..c8a845d9 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala @@ -0,0 +1,252 @@ +package vgb.game.models.storage + +import indigo.shared.collections.Batch +import indigo.shared.datatypes.Point +import io.circe.* +import io.circe.generic.auto.* +import io.circe.parser.* +import io.circe.syntax.* +import vgb.common.RoomType +import vgb.game.models.ScenarioMonster +import vgb.game.models.BoardOverlay +import vgb.game.models.Room +import vgb.game.models.sceneModels.CreatorModel +import vgb.common.Corridor +import vgb.common.Hexagon +import vgb.common.Door +import vgb.common.StartingLocation + +final case class ScenarioStorage( + id: Int, + title: String, + mapTileData: Option[MapTileDataStorage], + angle: Float, + additionalMonsters: List[String] +) { + override def toString(): String = + this.asJson.deepDropNullValues.noSpaces +} + +object ScenarioStorage: + def fromModel(model: CreatorModel) = + val roomCellMap = model.rooms + .map(r => r.worldCells.map(c => (c, r))) + .flatten + .toMap + + val overlays = assignExtendedCorridors(assignOverlaysToRoom(model.overlays, roomCellMap)) + val startLocationRooms = overlays + .filter(o => + o._2.overlayType match { + case _: StartingLocation => true + case _ => false + } + ) + .map(o => o._1) + val monsters = assignMonstersToRoom(model.monsters, roomCellMap) + val orderedRooms = model.rooms + .sortBy(r => startLocationRooms.contains(r.roomType)) + .toList + + orderedRooms match { + case head :: tail => + val scenario = ScenarioStorage( + model.scenarioTitle, + head, + overlays, + monsters, + Batch.fromList(tail) + ) + case _ => + ScenarioStorage( + 0, + model.scenarioTitle, + None, + 0, + List.empty + ) + } + + def apply( + title: String, + startingRoom: Room, + overlays: Batch[(RoomType, BoardOverlay)], + monsters: Batch[(RoomType, ScenarioMonster)], + rooms: Batch[Room] + ): ScenarioStorage = + ScenarioStorage( + 0, + title, + Some( + MapTileDataStorage( + startingRoom, + overlays, + monsters, + rooms :+ startingRoom, + rooms + )._1 + ), + 0, + List.empty + ) + + private def assignOverlaysToRoom( + overlays: Batch[BoardOverlay], + roomCellMap: Map[Point, Room] + ): Batch[(Room, BoardOverlay) | BoardOverlay] = + overlays.map { o => + // Get the rooms at the origin, and in all hexes around the origin + val connectedRooms = + Batch.fromIndexedSeq( + (IndexedSeq(o.origin) ++ + // Get all + (0 until 6) + .map(i => Hexagon.oddRowRotate(o.origin.toVector, o.origin.moveBy(0, 1).toVector, i.toByte).toPoint)) + .flatMap(cell => roomCellMap.get(cell)) + .distinct + ) + + // If even 1 room is found, we use the first room (closest to origin) + connectedRooms.headOption + .map { room => + ( + room, + o.overlayType match { + case _: Door | _: Corridor => + // Link the door or corridor to all surrounding rooms and update + // the origin to the rooms local position + o.copy( + linkedRooms = Some( + Batch.fromArray( + connectedRooms.map(r => r.roomType).toArray.distinct + ) + ), + origin = room.worldToLocal(o.origin) + ) + case _ => + // Update the overlays position so it is relative to the room's local position + o.copy(origin = room.worldToLocal(o.origin)) + } + ) + } + .getOrElse(o) + } + + private def assignMonstersToRoom( + monsters: Batch[ScenarioMonster], + roomCellMap: Map[Point, Room] + ): Batch[(RoomType, ScenarioMonster)] = + Batch.fromArray(monsters.toArray.flatMap { m => + // Get the rooms at the origin, and in all hexes around the origin + val connectedRooms = + Batch.fromIndexedSeq( + (IndexedSeq(m.initialPosition) ++ + // Get all + (0 until 6) + .map(i => + Hexagon + .oddRowRotate(m.initialPosition.toVector, m.initialPosition.moveBy(0, 1).toVector, i.toByte) + .toPoint + )) + .flatMap(cell => roomCellMap.get(cell)) + .distinct + ) + + // If even 1 room is found, we use the first room (closest to origin) + connectedRooms.headOption.map(room => + (room.roomType, m.copy(initialPosition = room.worldToLocal(m.initialPosition))) + ) + }) + + private def assignExtendedCorridors( + initialOverlays: Batch[(Room, BoardOverlay) | BoardOverlay] + ): Batch[(RoomType, BoardOverlay)] = + val unassignedOverlays: Batch[BoardOverlay] = Batch.fromArray( + initialOverlays.toArray.flatMap(o => + o match { + case o: BoardOverlay => + o.overlayType match + case _: Corridor => Some(o) + case _ => None + case _ => None + } + ) + ) + + val overlays = Batch.fromArray( + initialOverlays.toArray.flatMap(o => + o match { + case o: (Room, BoardOverlay) => Some(o) + case _ => None + } + ) + ) + + val corridors = overlays + .filter(o => + o._2.overlayType match { + case _: Corridor => true + case _ => false + } + ) + .toList + + val nonCorridors = overlays.filter(o => + o._2.overlayType match { + case _: Corridor => false + case _ => true + } + ) + + corridors match { + case head :: tail => + assignCorridor( + head._1, + head._2, + unassignedOverlays, + Batch.fromList(tail), + nonCorridors.map(o => (o._1.roomType, o._2)) + ) + case _ => overlays.map(o => (o._1.roomType, o._2)) + } + + private def assignCorridor( + room: Room, + corridor: BoardOverlay, + unassignedCorridors: Batch[BoardOverlay], + unchecked: Batch[(Room, BoardOverlay)], + attributed: Batch[(RoomType, BoardOverlay)] + ): Batch[(RoomType, BoardOverlay)] = + val worldPositions = corridor.worldCells + .map(p => + val w = room.localToWorld(p) + Batch.fromIndexedSeq( + (0 until 6) + .map(i => Hexagon.oddRowRotate(w.toVector, w.moveBy(0, 1).toVector, i.toByte).toPoint) + ) + ) + .flatten + + val newCorridors = + unassignedCorridors + .filter(c => c.worldCells.exists(p => worldPositions.contains(p))) + + val newUnchecked = + (unchecked ++ + newCorridors + .map(c => (room, c.copy(linkedRooms = corridor.linkedRooms, origin = room.worldToLocal(c.origin))))).toList + + newUnchecked match { + case head :: tail => + head match { + case (headRoom, headOverlay) => + assignCorridor( + headRoom, + headOverlay, + unassignedCorridors.filter(c => newCorridors.contains(c) == false), + Batch.fromList(tail), + attributed :+ (room.roomType, corridor) + ) + } + case _ => attributed :+ (room.roomType, corridor) + } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala index 2bd3947b..50c6ceed 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -20,6 +20,7 @@ import vgb.game.models.sceneModels.CreatorViewModel import vgb.game.models.GameRules import vgb.game.models.BoardOverlay import vgb.game.models.DragData +import vgb.game.models.storage.ScenarioStorage /** Placeholder scene for the space station * @@ -145,11 +146,13 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg case None => Outcome(viewModel.copy(dragging = Some(DragData(p, p, d, false)))) case _ => Outcome(viewModel) } - case MouseEvent.MouseDown(p, MouseButton.LeftMouseButton) => + case _: PointerEvent.PointerLeave => + Outcome(viewModel.copy(dragging = None, initialDragger = None)) + case e: PointerEvent.PointerDown if e.button == Some(MouseButton.LeftMouseButton) => ( viewModel.dragging match { case None => - val pos = Hexagon.screenPosToOddRow(HexComponent.height, p + viewModel.camera.position).toPoint + val pos = Hexagon.screenPosToOddRow(HexComponent.height, e.position + viewModel.camera.position).toPoint val data = model.monsters.find(m => m.initialPosition == pos) match { case Some(v) => Some(v) case None => model.overlays.find(o => o.worldCells.contains(pos)) @@ -165,8 +168,8 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg tyrianSubSystem.TyrianEvent .Send(GeneralMsgType.CloseContextMenu) ) - case MouseEvent.Move(p) => - val pos = Hexagon.screenPosToOddRow(HexComponent.height, p + viewModel.camera.position).toPoint + case e: PointerEvent.PointerMove => + val pos = Hexagon.screenPosToOddRow(HexComponent.height, e.position + viewModel.camera.position).toPoint val draggingData = viewModel.dragging.orElse( viewModel.initialDragger match { @@ -205,7 +208,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg else Outcome(viewModel) case None => Outcome(viewModel) } - case MouseEvent.MouseUp(p, MouseButton.LeftMouseButton) => + case e: PointerEvent.PointerUp if e.button == Some(MouseButton.LeftMouseButton) => viewModel.dragging match { case Some(d) if d.originalPos != d.pos => Outcome(viewModel.copy(dragging = None)) @@ -213,13 +216,13 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg case Some(d) if d.hasMoved => Outcome(viewModel.copy(dragging = None)) case _ => - val hexPos = Hexagon.screenPosToOddRow(HexComponent.height, p + viewModel.camera.position).toPoint + val hexPos = Hexagon.screenPosToOddRow(HexComponent.height, e.position + viewModel.camera.position).toPoint Outcome(viewModel.copy(dragging = None)) .addGlobalEvents( tyrianSubSystem.TyrianEvent .Send( GeneralMsgType.ShowContextMenu( - p, + e.position, ContextMenuComponent.getForCreator( model.rooms.find(r => r.worldCells.exists(rp => rp == hexPos)).map(r => r.roomType), model.monsters.find(m => m.initialPosition == hexPos), @@ -334,7 +337,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg context: SceneContext[Size], model: SceneModel, msg: CreatorMsgType - ) = + ): Outcome[SceneModel] = msg match { case CreatorMsgType.ChangeScenarioTitle(t) => val newTitle = t.slice(0, 30) @@ -381,9 +384,16 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg Outcome(model.copy(rooms = model.rooms.map(r1 => if r1 == room then newRoom else r1))) case None => Outcome(model) } - - case _ => + case CreatorMsgType.ExportFile => Outcome(model) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent.Send( + CreatorMsgType.ExportFileString( + model.scenarioTitle, + ScenarioStorage.fromModel(model).toString() + ) + ) + ) } def updateViewModelFromTyrian( diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/test/src/vgb/game/models/PlaceableTests.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/test/src/vgb/game/models/PlaceableTests.scala new file mode 100644 index 00000000..f11d344c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/test/src/vgb/game/models/PlaceableTests.scala @@ -0,0 +1,80 @@ +package vgb.game.models + +import indigo.shared.datatypes.Point +import indigo.shared.collections.Batch + +final case class TestPlaceable( + rotation: TileRotation, + origin: Point, + worldCells: Batch[Point] +) extends Placeable { + val minPoint: Point = origin + val maxPoint: Point = origin +} + +class PlaceableTests extends munit.FunSuite { + def checkConversionToWorld( + localPoint: Point, + origin: Point, + expectedResult: Point, + rotation: TileRotation = TileRotation.Default + )(implicit loc: munit.Location): Unit = + test( + s"""local ${localPoint} to world ${expectedResult} and back with origin ${origin} and rotation ${rotation}""" + ) { + val p = TestPlaceable(rotation, origin, Batch.empty) + + assertEquals( + expectedResult, + p.localToWorld(localPoint), + "Local point to world point fails" + ) + assertEquals( + localPoint, + p.worldToLocal(expectedResult), + "World point to local point fails" + ) + } + + // Simple tests for 0,0 local positions + checkConversionToWorld(Point(0, 0), Point(0, 0), Point(0, 0)) + checkConversionToWorld(Point(0, 0), Point(0, 1), Point(0, 1)) + checkConversionToWorld(Point(0, 0), Point(0, 2), Point(0, 2)) + checkConversionToWorld(Point(0, 0), Point(1, 0), Point(1, 0)) + checkConversionToWorld(Point(0, 0), Point(1, 1), Point(1, 1)) + checkConversionToWorld(Point(0, 0), Point(1, 2), Point(1, 2)) + + // Simple tests for 1,0 local positions + checkConversionToWorld(Point(1, 0), Point(0, 0), Point(1, 0)) + checkConversionToWorld(Point(1, 0), Point(0, 1), Point(1, 1)) + checkConversionToWorld(Point(1, 0), Point(0, 2), Point(1, 2)) + checkConversionToWorld(Point(1, 0), Point(1, 0), Point(2, 0)) + checkConversionToWorld(Point(1, 0), Point(1, 1), Point(2, 1)) + checkConversionToWorld(Point(1, 0), Point(1, 2), Point(2, 2)) + + // Simple tests for 0,1 local positions + checkConversionToWorld(Point(0, 1), Point(0, 0), Point(0, 1)) + + // This is where things get tricksy - In order to be correct on the + // hexagon grid the actual amount that the tile needs to move is 1, 1 not 0,1 + // as you might expect + checkConversionToWorld(Point(0, 1), Point(0, 1), Point(1, 2)) + checkConversionToWorld(Point(0, 1), Point(0, 2), Point(0, 3)) + checkConversionToWorld(Point(0, 1), Point(1, 0), Point(1, 1)) + + // Likewise, in order to be correct on the + // hexagon grid the actual amount that the tile needs to move is 2, 1 not 1,1 + // as you might expect + checkConversionToWorld(Point(0, 1), Point(1, 1), Point(2, 2)) + checkConversionToWorld(Point(0, 1), Point(1, 2), Point(1, 3)) + + // Now test a range of cells with a single rotation + checkConversionToWorld(Point(0, 0), Point(1, 1), Point(1, 1), TileRotation.DiagonalLeft) + checkConversionToWorld(Point(1, 0), Point(1, 1), Point(2, 2), TileRotation.DiagonalLeft) + checkConversionToWorld(Point(0, 1), Point(1, 1), Point(1, 2), TileRotation.DiagonalLeft) + checkConversionToWorld(Point(1, 1), Point(1, 1), Point(1, 3), TileRotation.DiagonalLeft) + checkConversionToWorld(Point(2, 1), Point(1, 1), Point(2, 4), TileRotation.DiagonalLeft) + checkConversionToWorld(Point(0, 2), Point(1, 1), Point(0, 2), TileRotation.DiagonalLeft) + checkConversionToWorld(Point(1, 2), Point(1, 1), Point(0, 3), TileRotation.DiagonalLeft) + checkConversionToWorld(Point(2, 2), Point(1, 1), Point(1, 4), TileRotation.DiagonalLeft) +} diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala index c1b8aa04..c9b761c5 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -4,6 +4,7 @@ import cats.effect.IO import indigo.shared.datatypes.Point import tyrian.* import tyrian.Html.* +import tyrian.cmds.File import vgb.common.CreatorMsgType import vgb.common.GloomhavenMsg import vgb.common.Menu @@ -18,6 +19,7 @@ import vgb.common.GeneralMsgType import vgb.common.MonsterType import vgb.common.BoardOverlayType import vgb.common.RoomType +import org.scalajs.dom object CreatorScene extends TyrianScene { type SceneModel = CreatorModel @@ -42,6 +44,11 @@ object CreatorScene extends TyrianScene { ), Cmd.None ) + case CreatorMsgType.ShowImportDialog => + (model, File.select(Array("application/json"))(f => CreatorMsgType.ImportFileSelected(f))) + case CreatorMsgType.ExportFileString(title, json) => + (model, Download.string(title, "application/json", json)) + case _ => (model, Cmd.None) } @@ -116,7 +123,7 @@ object CreatorModel: Menu() .add(Some(MenuItem("Create New", CreatorMsgType.CreateNewScenario))) .add(MenuSeparator()) - .add(Some(MenuItem("Export", CreatorMsgType.ShowExportDialog))) + .add(Some(MenuItem("Export", CreatorMsgType.ExportFile))) .add(Some(MenuItem("Import", CreatorMsgType.ShowImportDialog))) .add(MenuSeparator()), false, diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1b.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1b.webp new file mode 100644 index 0000000000000000000000000000000000000000..797a5c8f7cb9a745445c5c141f00ae11cc6e455b GIT binary patch literal 6982 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 YQL>OK3^L!~00000000000000001Lx@O8@`> literal 0 HcmV?d00001 diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/door-altar.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/door-altar.webp new file mode 100644 index 0000000000000000000000000000000000000000..6bd816cd3978ed76049bc370d0e38a5117825997 GIT binary patch literal 2312 zcmV+j3HSC=Nk&Eh2><|BMM6+kP&il$0000G0000^003D406|PpNSFcu00E#y+qNl5 zI_ExwBg(dI+qP}nwr$(CZQE?y?hd_oPcd#h{C7l50GLy*b8EO4Y?I~O6(;>zbJZpi z&Hjhpj~*?|Y{1p?J5C?{Z)q~Lm|WwAPBH&7*kdJ@b!V7F^@oiWt6;(z|4=+5hx0Q_ zxO#lWDbB&g${x?Mq#EcVG{qTzZ(FgG8dyFMEboNvLOj4{XydY zE=&O*cC`MSix5Tj=VEblwEL8kaO7w~1~K}_{w_rH&)lRagosQjb4ep%{aGUii(SgH zF(^d*>)viej0KtG$i5{^!u*$!N!;ST>NhkIBK>Ynr^N6h$kdcmekbw&HWo^iGWJv{ zKbT?QH(Z1$vOllNKEk{mKIJ6N&n{jV_w|2^5&brzU&&4*YsZnjel!06q1615+evgYrd#=+ZRii{$RN2&pN`rB|6!0H0Z>u{Enn!? z`*&G-g#iE{laz!bezI8fXdzW%_#Pl4vNS7$7SbQpQxFkiXGKm$t@6WQFT_=C@?5t< za9K)(c>6~GV!G(@f(#7AG;71A(w{U^z+k!TCCxlPkMM%w%#otsXWSg&^%)o#kBT=% zfkl6sK)X~mpr9Efhc9WG5<9~N@s~Z*`yG-Q043Gs4J595Q8VJV38{Q;RbpUDWK5P7 z#oOUEk5_0-Iz^TxhG>o$1LOaSOZ0Sc2`q}~Him@w%Qh-lSSoixi|vmwez3T+)93tS z!L?}-tnZ)n_Xo7IWhAgg%(yv3{L^+0uuZA*QMzJ6YGI+~< zvE@8wZg@G$_;xb6+V%$)raIqTo<0z$F2qI;h^_mK zeLMZQ4EyU{?GRZJXCL0(uaKo6BLD#Y(Rp~LvhjL$a&%+|r*mB*6!!1s}IWAL_3 zj~Zbctx@5+*Mz|R#w=V$$Iw*={x-RPa6 zbB~}<2i7ffXHF`uu+wvKVd)bR5^f&l z%mp@^i#x>H7&A`*GVFK+chh~NXs&((@jRNF2@mNtKQp%o3Meg)?01$W$9ANJQzhhXr)rFaslHM||jD_o2Z%cV3=N)}|D$6#T2moB5HiVZFK zn{SxKk-#~1SY+LJ(l&Hb$tma>Jc} zc=k>8p!Wtu9~5OOI&#W~^Awk$S(3c2C<~w#H6RoXq2T!#fxl}!8c{|m?70xPsN?AG zc0W@$ape;nZXQ?(uYFNLsyC+?m0$HLDZFe7S885**Cp79wEtI-{bIZ42|RL0w?7#* z<+uwM3Mp)+($tWUau~I5kQM&N&|{93yEzcS`IGad#ClXg(mp_?#=~fTw6+Agxv81{ zxUolr<@8DPKA7qkS6qGGKstt>7E`S2OBDN8n+W$Nl_35rk74Eu+{C^HVuC$&ryTB6 z9=ID>t(8lv0f^wA!m!6J_e2tIddSpJbRFFvEVfp!$D1emRGFp`M_HjS_QRTjtGb#` zIkw*O%nsLYP}n^D5H)<<9^8D?=L(^3T2E0lEPG6xlooI+&#ce#=&UWpkUBP?^^&=! z@ZJWNvoK(cIqu|&_E0tpst;89cyeq0QiR2__ zHszSlUSMZ&F?ofmuH9ta>{AnD3(UD=iHPdjrM8T5I~F^9j2D@`bV&GSxhT5@C{Y=N zS56n(8k%c*(xy3S`m7dcE-s0fxCZNOJ?r0_N>*^wKaQk)mBc(uyh*aS=cVX+NIeY? zXyZH1I;?adQ9s<07|C2(?AkTBYbh7UjtqL*nk``3UyiB@Z3sOUh-TaLq~%wix%(boh(kwW9`Z;B$7zq@#0 z7HmF$-V6~reANh#;oGj&&}zN@s_q>zq`_9tu@C>j=lZ Date: Wed, 16 Aug 2023 07:37:08 +0100 Subject: [PATCH 59/60] Export now works correctly from Creator --- VirtualGloomhavenBoard/Indigo/.jvmopts | 1 - .../src/vgb/game/models/BoardOverlay.scala | 3 - .../vgb/game/models/storage/DoorStorage.scala | 24 +++++++- .../models/storage/MapTileDataStorage.scala | 59 +++++++++++++++++-- .../game/models/storage/OverlayStorage.scala | 18 ++++++ .../game/models/storage/ScenarioStorage.scala | 7 +-- .../src/vgb/game/scenes/CreatorScene.scala | 1 + .../src/vgb/ui/scenes/CreatorScene.scala | 4 +- 8 files changed, 103 insertions(+), 14 deletions(-) diff --git a/VirtualGloomhavenBoard/Indigo/.jvmopts b/VirtualGloomhavenBoard/Indigo/.jvmopts index 58808e04..3457f79c 100644 --- a/VirtualGloomhavenBoard/Indigo/.jvmopts +++ b/VirtualGloomhavenBoard/Indigo/.jvmopts @@ -2,4 +2,3 @@ -Xms1G -Xmx8G -XX:+UseG1GC --Xmax-inlines:64 diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala index a1b8f2b9..e7caf6c4 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala @@ -17,12 +17,9 @@ final case class BoardOverlay( val worldCells = overlayType.cells.map(localToWorld) def rotate() = - IndigoLogger.consoleLog(Vector2.fromPoint(rotationPoint).toString()) - val rotatedOrigin = Hexagon.oddRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) - IndigoLogger.consoleLog(rotatedOrigin.toString()) this.copy( origin = rotatedOrigin.toPoint, rotation = rotation.nextRotation(overlayType.verticalAssetName != None) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala index c27fe364..790fe2e2 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala @@ -1,7 +1,7 @@ package vgb.game.models.storage +import indigo.* import vgb.game.models.Room -import indigo.shared.collections.Batch import vgb.common.RoomType import vgb.game.models.BoardOverlay import vgb.game.models.ScenarioMonster @@ -44,6 +44,28 @@ object DoorStorage: } ) + IndigoLogger.consoleLog("door?") + IndigoLogger.consoleLog( + doorsForRoom + .flatMap(d => + d.linkedRooms match { + case Some(links) => + Batch.fromArray( + links + .filter(l => room.roomType != l) + .toArray + .flatMap(l => + allRooms + .find(r => r.roomType == l) + .map(r => (d, r)) + ) + ) + case None => Batch.empty + } + ) + .toString() + ) + doorsForRoom .flatMap(d => d.linkedRooms match { diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala index 6ceb437f..8539f232 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala @@ -1,7 +1,11 @@ package vgb.game.models.storage +import indigo.* +import io.circe.* +import io.circe.generic.auto.* +import io.circe.parser.* +import io.circe.syntax.* import vgb.game.models.Room -import indigo.shared.collections.Batch import vgb.common.RoomType import vgb.game.models.BoardOverlay import vgb.game.models.ScenarioMonster @@ -14,6 +18,16 @@ final case class MapTileDataStorage( turns: Byte ) +implicit val encodeMapTileDataStorage: Encoder[MapTileDataStorage] = new Encoder[MapTileDataStorage] { + final def apply(a: MapTileDataStorage): Json = Json.obj( + ("ref", Json.fromString(a.ref)), + ("doors", Json.fromValues(a.doors.map(d => d.asJson))), + ("overlays", Json.fromValues(a.overlays.map(o => o.asJson))), + ("monsters", Json.fromValues(a.monsters.map(m => m.asJson))), + ("turns", Json.fromInt(a.turns.toInt)) + ) +} + object MapTileDataStorage: def apply( room: Room, @@ -29,7 +43,7 @@ object MapTileDataStorage: .map(o => if o._1 == room.roomType then o._2 else o) .foldLeft((Batch.empty[OverlayStorage], Batch.empty[(RoomType, BoardOverlay)]))((cols, o) => o match { - case o: BoardOverlay => (cols._1 :+ OverlayStorage.fromModel(o), cols._2) + case o: BoardOverlay => (cols._1 :+ OverlayStorage.fromModel(o, room), cols._2) case o: (RoomType, BoardOverlay) => (cols._1, cols._2 :+ o) } ) @@ -48,8 +62,7 @@ object MapTileDataStorage: else (Batch.empty, monsters) val (doors, newRemainingRooms) = - if roomNeedsOutput then - DoorStorage.fromRooms(room, remainingOverlays, remainingMonsters, allRooms, remainingRooms) + if roomNeedsOutput then getDoorsForRoom(room, overlays, remainingMonsters, allRooms, remainingRooms) else (Batch.empty, remainingRooms) ( @@ -62,3 +75,41 @@ object MapTileDataStorage: ), newRemainingRooms.filter(r => r != room) ) + + private def getDoorsForRoom( + room: Room, + overlays: Batch[(RoomType, BoardOverlay)], + remainingMonsters: Batch[(RoomType, ScenarioMonster)], + allRooms: Batch[Room], + remainingRooms: Batch[Room] + ): (Batch[DoorStorage], Batch[Room]) = + DoorStorage.fromRooms(room, overlays, remainingMonsters, allRooms, remainingRooms) match { + case d if d._1.isEmpty => + // No doors can be found, so attempt to find doors that are linked, but not yet associated with this room + DoorStorage.fromRooms( + room, + overlays + .map(o => + o._2.linkedRooms match { + // This door has this room as a match, so we can use it + case Some(r) if r.contains(room.roomType) => + // Get the original room the door was associated as + allRooms.find(r => r.roomType == o._1) match { + case Some(originalRoom) => + ( + // Change the associated room type to this room + room.roomType, + // Move the door to the new room origin + o._2.copy(origin = room.worldToLocal(originalRoom.localToWorld(o._2.origin))) + ) + case None => o + } + case _ => o + } + ), + remainingMonsters, + allRooms, + remainingRooms + ) + case d => d + } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala index 76463051..7a561e7b 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala @@ -8,6 +8,8 @@ import indigo.shared.collections.Batch import indigo.shared.datatypes.RGB import vgb.game.models.TileRotation import indigo.shared.datatypes.Point +import vgb.game.models.GameRules.rotateOverlay +import vgb.game.models.Room final case class OverlayStorage( ref: OverlayStorageRef, @@ -221,6 +223,22 @@ object OverlayStorage: overlay.worldCells.map(c => CellStorage.fromPoint(c).toList).toList ) + def fromModel(overlay: BoardOverlay, room: Room) = + val newRotation = + Math.max(overlay.rotation.toByte(), room.rotation.toByte()) - + Math.min(overlay.rotation.toByte(), room.rotation.toByte()) + + OverlayStorage( + getRefForType(overlay), + overlay.id, + overlay.rotation.toString(), + overlay + .copy(rotation = TileRotation.fromByte(newRotation.toByte)) + .worldCells + .map(c => CellStorage.fromPoint(c).toList) + .toList + ) + private def getRefForType(overlay: BoardOverlay) = overlay.overlayType match { case c: Corridor => diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala index c8a845d9..52423d78 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala @@ -1,7 +1,6 @@ package vgb.game.models.storage -import indigo.shared.collections.Batch -import indigo.shared.datatypes.Point +import indigo.* import io.circe.* import io.circe.generic.auto.* import io.circe.parser.* @@ -50,7 +49,7 @@ object ScenarioStorage: orderedRooms match { case head :: tail => - val scenario = ScenarioStorage( + ScenarioStorage( model.scenarioTitle, head, overlays, @@ -83,7 +82,7 @@ object ScenarioStorage: overlays, monsters, rooms :+ startingRoom, - rooms + rooms :+ startingRoom )._1 ), 0, diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala index 50c6ceed..061dbefd 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -394,6 +394,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg ) ) ) + case _ => Outcome(model) } def updateViewModelFromTyrian( diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala index c9b761c5..274fd58f 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -4,6 +4,7 @@ import cats.effect.IO import indigo.shared.datatypes.Point import tyrian.* import tyrian.Html.* +import tyrian.cmds.Download import tyrian.cmds.File import vgb.common.CreatorMsgType import vgb.common.GloomhavenMsg @@ -20,6 +21,7 @@ import vgb.common.MonsterType import vgb.common.BoardOverlayType import vgb.common.RoomType import org.scalajs.dom +import indigo.shared.IndigoLogger object CreatorScene extends TyrianScene { type SceneModel = CreatorModel @@ -47,7 +49,7 @@ object CreatorScene extends TyrianScene { case CreatorMsgType.ShowImportDialog => (model, File.select(Array("application/json"))(f => CreatorMsgType.ImportFileSelected(f))) case CreatorMsgType.ExportFileString(title, json) => - (model, Download.string(title, "application/json", json)) + (model, Download.fromString(title + ".json", "application/json", json)) case _ => (model, Cmd.None) From 880eca0708aba99169278c5f1aeec2cbbd2b88ac Mon Sep 17 00:00:00 2001 From: David North Date: Fri, 15 Sep 2023 20:12:02 +0100 Subject: [PATCH 60/60] Imports now work correctly within the creator --- .../vgb-common/src/vgb/common/CommonMsg.scala | 5 +- .../vgb-common/src/vgb/common/RoomType.scala | 9 +- .../models/sceneModels/CreatorModel.scala | 9 ++ .../vgb/game/models/storage/DoorStorage.scala | 45 +++++---- .../models/storage/MapTileDataStorage.scala | 11 +++ .../game/models/storage/OverlayStorage.scala | 4 +- .../vgb/game/models/storage/RoomStorage.scala | 5 +- .../game/models/storage/ScenarioStorage.scala | 92 +++++++++++++++++++ .../src/vgb/game/scenes/CreatorScene.scala | 12 ++- .../Indigo/vgb-ui/src/vgb/ui/Main.scala | 22 +++++ .../ui/models/components/MenuComponent.scala | 4 +- .../src/vgb/ui/scenes/CreatorScene.scala | 15 ++- 12 files changed, 194 insertions(+), 39 deletions(-) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala index ed79094a..345a4090 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala @@ -14,6 +14,7 @@ trait GloomhavenMsg enum GeneralMsgType extends GloomhavenMsg: case ShowContextMenu(position: Point, menu: Menu) case CloseContextMenu + case ShowImportDialog(msg: (String, String, String) => GloomhavenMsg) enum CreatorMsgType extends GloomhavenMsg: case ChangeMonsterLevel(pos: Point, m: MonsterType, playerNum: Byte, monsterLevel: MonsterLevel) @@ -23,13 +24,11 @@ enum CreatorMsgType extends GloomhavenMsg: case RotateRoom(r: RoomType) case RemoveRoom(r: RoomType) case CreateNewScenario - case ShowImportDialog - case ImportFileSelected(file: dom.File) case ChangeScenarioTitle(title: String) case UpdateDragMenu(sections: Batch[DragDropSection]) case SetSelectedDragSection(sectionName: String) case NewDragStart(dragItem: RoomType | BoardOverlayType | MonsterType) case DragEnd - case SelectFile + case ImportFile(name: String, path: String, data: String) case ExportFile case ExportFileString(title: String, json: String) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala index 362e11d1..994f9161 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala @@ -41,7 +41,6 @@ enum RoomType(val baseGame: BaseGame, val mapRef: String, val offset: Point, val ), Size(432, 244) ) - /* { tileset: "gloomhaven", @@ -71,3 +70,11 @@ enum RoomType(val baseGame: BaseGame, val mapRef: String, val offset: Point, val ] } */ + +object RoomType: + def fromRef(baseGame: BaseGame, ref: String): Option[RoomType] = + RoomType.values + .find(r => + r.baseGame == baseGame && + r.mapRef.toLowerCase() == ref.toLowerCase() + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala index dc7f8a76..e18adfc1 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala @@ -54,6 +54,15 @@ object CreatorModel: Batch.empty ) + def apply(scenarioTitle: String, baseGame: BaseGame): CreatorModel = + CreatorModel( + scenarioTitle, + baseGame, + Batch.empty, + Batch.empty, + Batch.empty + ) + def fromJson(json: String): Either[String, CreatorModel] = decode[CreatorStorage](json) match { case Right(value) => value.toModel() diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala index 790fe2e2..b797d2f0 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala @@ -7,6 +7,7 @@ import vgb.game.models.BoardOverlay import vgb.game.models.ScenarioMonster import vgb.common.Door import vgb.common.Corridor +import vgb.common.BaseGame final case class DoorStorage( subType: String, @@ -18,7 +19,27 @@ final case class DoorStorage( room2X: Int, room2Y: Int, mapTileData: MapTileDataStorage -) +): + def toModel(baseGame: BaseGame) = + OverlayStorage( + this.toOverlayStorageRef(), + 0, + this.direction, + List(List(this.room1X, this.room1Y)) + ).toModel(baseGame) + + def toOverlayStorageRef() = + OverlayStorageRef( + "door", + Some(subType), + material, + size, + Some(List(mapTileData.ref)), + None, + None, + None, + None + ) object DoorStorage: def fromRooms( @@ -44,28 +65,6 @@ object DoorStorage: } ) - IndigoLogger.consoleLog("door?") - IndigoLogger.consoleLog( - doorsForRoom - .flatMap(d => - d.linkedRooms match { - case Some(links) => - Batch.fromArray( - links - .filter(l => room.roomType != l) - .toArray - .flatMap(l => - allRooms - .find(r => r.roomType == l) - .map(r => (d, r)) - ) - ) - case None => Batch.empty - } - ) - .toString() - ) - doorsForRoom .flatMap(d => d.linkedRooms match { diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala index 8539f232..ec2eaa44 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala @@ -28,6 +28,17 @@ implicit val encodeMapTileDataStorage: Encoder[MapTileDataStorage] = new Encoder ) } +implicit val decodeMapTileDataStorage: Decoder[MapTileDataStorage] = new Decoder[MapTileDataStorage] { + final def apply(c: HCursor): Decoder.Result[MapTileDataStorage] = + for { + ref <- c.downField("ref").as[String] + doors <- c.downField("doors").as[List[DoorStorage]] + overlays <- c.downField("overlays").as[List[OverlayStorage]] + monsters <- c.downField("monsters").as[List[ScenarioMonsterStorage]] + turns <- c.downField("turns").as[Byte] + } yield new MapTileDataStorage(ref, doors, overlays, monsters, turns) +} + object MapTileDataStorage: def apply( room: Room, diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala index 7a561e7b..db2ea27e 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala @@ -34,9 +34,7 @@ final case class OverlayStorage( .foldLeft(Option.empty[Point])((p, c) => p.map(c.min).orElse(Some(c))) .getOrElse(Point.zero) - val o = overlay.copy(origin = minCell - minPoint) - IndigoLogger.consoleLog(o.worldCells.toString()) - o + overlay.copy(origin = minCell - minPoint) } private def decodeOverlay(baseGame: BaseGame) = diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala index 107bc82f..18814e6c 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala @@ -13,15 +13,12 @@ final case class RoomStorage( rotationPoint: CellStorage ) { def toModel(baseGame: BaseGame): Either[String, Room] = - val roomType = RoomType.values - .find(r => r.baseGame == baseGame && r.mapRef.toLowerCase() == data.ref.toLowerCase()) - roomType match { + RoomType.fromRef(baseGame, data.ref) match { case Some(roomType) => Right( Room(roomType, Point(data.origin.x, data.origin.y), TileRotation.fromByte(data.turns)) ) case None => Left(s"""Map tile ${data.ref} does not exist for ${baseGame}""") - } } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala index 52423d78..cd900b4c 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala @@ -14,16 +14,92 @@ import vgb.common.Corridor import vgb.common.Hexagon import vgb.common.Door import vgb.common.StartingLocation +import vgb.common.BaseGame +import vgb.game.models.TileRotation final case class ScenarioStorage( id: Int, title: String, + baseGame: Option[String], mapTileData: Option[MapTileDataStorage], angle: Float, additionalMonsters: List[String] ) { override def toString(): String = this.asJson.deepDropNullValues.noSpaces + + def toCreatorModel(): Either[String, CreatorModel] = + val baseGame = this.baseGame match { + case Some(value) => + BaseGame.values.find(g => g.toString().toLowerCase() == value) match { + case Some(bg) => bg + case None => BaseGame.Gloomhaven + } + case None => BaseGame.Gloomhaven + } + + val model = CreatorModel(this.title, baseGame) + + this.mapTileData match { + case Some(data) => decodeMapTileData(Point.zero, Point.zero, data, model) + case None => Right(model) + } + + private def decodeMapTileData( + origin: Point, + localOffset: Point, + data: MapTileDataStorage, + model: CreatorModel + ): Either[String, CreatorModel] = + RoomType.fromRef(model.baseGame, data.ref) match { + case Some(roomType) => + val room = Room(roomType, origin.moveBy(localOffset), TileRotation.fromByte(data.turns)) + val overlays = data.overlays.map(o => o.toModel(model.baseGame).map(o => o.copy(origin = room.localToWorld(o.origin)))) + val monsters = data.monsters.map(m => m.toModel(model.baseGame).map(m => m.copy(initialPosition = room.localToWorld(m.initialPosition)))) + + val errors = + overlays.collect { case Left(e) => e } ++ + monsters.collect { case Left(e) => e } + + errors.headOption match { + case Some(value) => Left(value) + case _ => + val newModel = model.copy( + rooms = + if model.rooms.exists(r => r.roomType == roomType) then model.rooms + else model.rooms :+ room, + overlays = model.overlays ++ Batch.fromList(overlays.collect { case Right(o) => o }), + monsters = model.monsters ++ Batch.fromList(monsters.collect { case Right(m) => m }) + ) + + decodeDoorData(room, data.doors, newModel) + } + + case None => Left(s"""Map tile ${data.ref} does not exist for ${baseGame}""") + } + + private def decodeDoorData(room: Room, doors: List[DoorStorage], model: CreatorModel): Either[String, CreatorModel] = + doors + .foldLeft(Right(model).asInstanceOf[Either[String, CreatorModel]])((m, d) => + m match { + case Right(newModel) => + val door = d + .toModel(model.baseGame) + .map(d1 => d1.copy(origin = room.localToWorld(Point(d.room1X, d.room1Y)))) + + door match { + case Right(d2) => + decodeMapTileData( + d2.origin, + Point(d.room2X, d.room2Y), + d.mapTileData, + newModel.copy(overlays = newModel.overlays :+ d2) + ) + case Left(d2) => Left(d2) + } + case Left(_) => m + } + ) } object ScenarioStorage: @@ -51,6 +127,7 @@ object ScenarioStorage: case head :: tail => ScenarioStorage( model.scenarioTitle, + model.baseGame, head, overlays, monsters, @@ -60,6 +137,10 @@ object ScenarioStorage: ScenarioStorage( 0, model.scenarioTitle, + model.baseGame match { + case BaseGame.Gloomhaven => None + case _ => Some(model.baseGame.toString().toLowerCase()) + }, None, 0, List.empty @@ -68,6 +149,7 @@ object ScenarioStorage: def apply( title: String, + baseGame: BaseGame, startingRoom: Room, overlays: Batch[(RoomType, BoardOverlay)], monsters: Batch[(RoomType, ScenarioMonster)], @@ -76,6 +158,10 @@ object ScenarioStorage: ScenarioStorage( 0, title, + baseGame match { + case BaseGame.Gloomhaven => None + case _ => Some(baseGame.toString().toLowerCase()) + }, Some( MapTileDataStorage( startingRoom, @@ -89,6 +175,12 @@ object ScenarioStorage: List.empty ) + def fromJson(json: String): Either[String, ScenarioStorage] = + decode[ScenarioStorage](json) match { + case Right(value) => Right(value) + case Left(err) => Left(err.getMessage()) + } + private def assignOverlaysToRoom( overlays: Batch[BoardOverlay], roomCellMap: Map[Point, Room] diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala index 061dbefd..42799d11 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -57,7 +57,7 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg EventFilters.AllowAll val subSystems: Set[SubSystem] = - Set(tyrianSubSystem) + Set() def updateModel( context: SceneContext[Size], @@ -394,6 +394,16 @@ final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg ) ) ) + case CreatorMsgType.ImportFile(_, _, data) => + ScenarioStorage.fromJson(data) match { + case Right(scenario) => + scenario.toCreatorModel() match { + case Right(newModel) => + Outcome(newModel).addGlobalEvents(StorageEvent.Save(saveSlot, newModel.toString())) + case _ => Outcome(model) + } + case _ => Outcome(model) + } case _ => Outcome(model) } diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala index 8e1a371e..879c9013 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala @@ -18,6 +18,11 @@ import vgb.common.{MenuItem, MenuSeparator} import vgb.ui.models.UiModel import vgb.ui.scenes.CreatorModel import tyrian.cmds.Logger +import tyrian.cmds.File +import indigo.shared.IndigoLogger +import tyrian.cmds.FileReader + +import org.scalajs.dom enum Msg: case NoOp @@ -29,6 +34,8 @@ enum Msg: case CloseContextItem(itemId: Byte) case CloseContextMenu case ToggleMainMenu + case ReadFile(file: dom.File, msg: (String, String, String) => GloomhavenMsg) + case FileRead(file: FileReader.Result[String], msg: (String, String, String) => GloomhavenMsg) @JSExportTopLevel("TyrianApp") object Main extends TyrianApp[Msg, Model]: @@ -94,6 +101,19 @@ object Main extends TyrianApp[Msg, Model]: model.copy(sceneModel = model.sceneModel.toggleMainMenu()), Cmd.None ) + case Msg.ReadFile(file, msg) => + ( + model, + FileReader.readText(file)(r => Msg.FileRead(r, msg)) + ) + case Msg.FileRead(fileResult, msg) => + update(model)( + fileResult match { + case _: FileReader.Result.Error[String] => Msg.NoOp + case FileReader.Result.File(name, path, data) => + Msg.IndigoReceive(msg(name, path, data)) + } + ) def view(model: Model): Html[Msg] = val sceneModel = model.scene.getModel(model) @@ -198,6 +218,8 @@ object Main extends TyrianApp[Msg, Model]: ) case GeneralMsgType.CloseContextMenu => (model.copy(sceneModel = model.sceneModel.updateContextMenu(None)), Cmd.None) + case GeneralMsgType.ShowImportDialog(msg) => + (model, File.select(Array("application/json"))(f => Msg.ReadFile(f, msg))) } case _ => val (sceneModel, cmd) = model.scene.update(msg, model.scene.getModel(model)) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala index 10c276c2..87ba1928 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala @@ -9,6 +9,7 @@ import vgb.common.MenuLink import vgb.common.MenuSeparator import indigo.shared.collections.Batch import vgb.common.MenuItemTrait +import vgb.common.GeneralMsgType object MenuComponent: def render(menu: Menu, visible: Boolean): Html[Msg] = @@ -84,7 +85,8 @@ object MenuComponent: (item match { case item: MenuItem => List(onClick(item.cmd match { - case Some(c) => Msg.IndigoSend(c) + case Some(m: GeneralMsgType.ShowImportDialog) => Msg.IndigoReceive(m) + case Some(c) => Msg.IndigoSend(c) case None => parentItem match { case Some(p) => Msg.CloseContextItem(p.id) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala index 274fd58f..1348d205 100644 --- a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -22,6 +22,8 @@ import vgb.common.BoardOverlayType import vgb.common.RoomType import org.scalajs.dom import indigo.shared.IndigoLogger +import scala.util.matching.Regex +import java.util.Base64 object CreatorScene extends TyrianScene { type SceneModel = CreatorModel @@ -46,8 +48,15 @@ object CreatorScene extends TyrianScene { ), Cmd.None ) - case CreatorMsgType.ShowImportDialog => - (model, File.select(Array("application/json"))(f => CreatorMsgType.ImportFileSelected(f))) + case CreatorMsgType.ImportFile(name, path, data) => + val regex = "^data:([a-z\\/]+);base64,".r + val decodedData = Base64 + .getDecoder() + .decode(regex.replaceAllIn(data, _ => "")) + .map(_.toChar) + .mkString + + (model, Cmd.Emit(CreatorMsgType.ImportFile(name, path, decodedData))) case CreatorMsgType.ExportFileString(title, json) => (model, Download.fromString(title + ".json", "application/json", json)) @@ -126,7 +135,7 @@ object CreatorModel: .add(Some(MenuItem("Create New", CreatorMsgType.CreateNewScenario))) .add(MenuSeparator()) .add(Some(MenuItem("Export", CreatorMsgType.ExportFile))) - .add(Some(MenuItem("Import", CreatorMsgType.ShowImportDialog))) + .add(Some(MenuItem("Import", GeneralMsgType.ShowImportDialog(CreatorMsgType.ImportFile.apply)))) .add(MenuSeparator()), false, Batch.empty,