diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..cf7b88e4 --- /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@v14 + with: + java-version: adopt@1.11 + - uses: jodersky/setup-mill@master + with: + mill-version: 0.11.1 + - name: Compile & Test + run: bash ci.sh diff --git a/.gitignore b/.gitignore index f574456d..22ac6405 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,43 @@ 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 + +# parcel +.parcel-cache +dist 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: diff --git a/VirtualGloomhavenBoard/Indigo/.jvmopts b/VirtualGloomhavenBoard/Indigo/.jvmopts new file mode 100644 index 00000000..3457f79c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/.jvmopts @@ -0,0 +1,4 @@ +-Xss8m +-Xms1G +-Xmx8G +-XX:+UseG1GC diff --git a/VirtualGloomhavenBoard/Indigo/.mill-version b/VirtualGloomhavenBoard/Indigo/.mill-version new file mode 100644 index 00000000..af88ba82 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/.mill-version @@ -0,0 +1 @@ +0.11.1 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/.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..0b1b5ba8 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/build.sc @@ -0,0 +1,87 @@ +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 + +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() + fastLinkJS() + } + } +} + +trait VgbModule extends ScalaJSModule { + def scalaVersion = "3.3.0" + def scalaJSVersion = "1.13.1" + + val indigoVersion = "0.15.0-RC4" + val tyrianVersion = "0.7.2-SNAPSHOT" + val circeVersion = "0.14.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", + ivy"io.circe::circe-core::$circeVersion", + ivy"io.circe::circe-generic::$circeVersion", + ivy"io.circe::circe-parser::$circeVersion" + ) + + 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 { + + 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..17ebadc1 --- /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/static", + "watcherGlob": "**" + }, + "alias": { + "assert": false, + "console": false, + "crypto": false, + "buffer": false, + "stream": false + } +} diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BaseGame.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BaseGame.scala new file mode 100644 index 00000000..aa406408 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BaseGame.scala @@ -0,0 +1,5 @@ +package vgb.common + +enum BaseGame(val shortName: String): + case Gloomhaven extends BaseGame("gh") + case Frosthaven extends BaseGame("fh") diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala new file mode 100644 index 00000000..f94a24c3 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/BoardOverlayType.scala @@ -0,0 +1,125 @@ +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] + val flag: Flag + 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 codedName = name.toLowerCase().replace(" ", "-") + val assetName: AssetName = AssetName(s"""${baseGame.shortName}-${codedName}""") + +enum DifficultTerrain( + val baseGame: BaseGame, + val cells: Batch[Point] +) extends BoardOverlayType: + val flag: Flag = Flag.DifficultTerrain + val verticalAssetName = None + case Rubble extends DifficultTerrain(BaseGame.Gloomhaven, Batch(Point(0, 0))) + +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)), None) + +enum Hazard(val baseGame: BaseGame, val cells: Batch[Point]) extends BoardOverlayType: + 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))) + +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 + +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 + 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 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" + case Coin(_, _) => "Coin" + + case Chest(val baseGame: BaseGame, val treasureType: TreasureChestType) extends Treasure(Flag.TreasureChest) + 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 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 verticalAssetName = None + case Rock extends Wall(BaseGame.Gloomhaven, Batch(Point(0, 0))) 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..345a4090 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/CommonMsg.scala @@ -0,0 +1,34 @@ +package vgb.common + +import indigo.Point +import indigo.shared.collections.Batch + +import org.scalajs.dom + +/** A message from the VGB app + */ +trait GloomhavenMsg + +/** General messages that can be used across many scenes + */ +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) + case RemoveMonster(pos: Point, m: MonsterType) + case RotateOverlay(id: Int, o: BoardOverlayType) + case RemoveOverlay(id: Int, o: BoardOverlayType) + case RotateRoom(r: RoomType) + case RemoveRoom(r: RoomType) + case CreateNewScenario + case ChangeScenarioTitle(title: String) + case UpdateDragMenu(sections: Batch[DragDropSection]) + case SetSelectedDragSection(sectionName: String) + case NewDragStart(dragItem: RoomType | BoardOverlayType | MonsterType) + case DragEnd + 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/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-common/src/vgb/common/Expansion.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Expansion.scala new file mode 100644 index 00000000..d3e78565 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Expansion.scala @@ -0,0 +1,13 @@ +package vgb.common +import vgb.common.BaseGame + +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-common/src/vgb/common/Flag.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Flag.scala new file mode 100644 index 00000000..78d62653 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Flag.scala @@ -0,0 +1,36 @@ +package vgb.common + +enum Flag(val value: Int): + case Room extends Flag(1) + case Obstacle extends Flag(2) + case DifficultTerrain extends Flag(4) + case Hazard extends Flag(8) + case Trap extends Flag(16) + case Rift extends Flag(32) + case Wall extends Flag(64) + case Door extends Flag(128) + case Corridor extends Flag(256) + case TreasureChest extends Flag(512) + case Coin extends Flag(1024) + case Token extends Flag(2048) + case StartingLocation extends Flag(4096) + case Highlight extends Flag(8192) + case Monster extends Flag(16384) + case Character extends Flag(32768) + case Summons extends Flag(65536) + case Hidden extends Flag(131072) + +object Flag: + lazy val All = Flag.values.foldLeft(0)((v, f) => v | f.value) + lazy val MinimiseCoin = (Flag.All - Flag.Coin.value - Flag.Token.value - Flag.Room.value - Flag.Hidden.value - Flag.Highlight.value) + lazy val MinimiseToken = (Flag.Coin.value | Flag.TreasureChest.value | Flag.Monster.value | Flag.Character.value) + +implicit class FlagOps(left: Int) { + def +(right: Flag): Int = + if (left & right.value) == 0 then left + right.value + else left + + def -(right: Flag): Int = + if (left & right.value) == 0 then left - right.value + else left +} diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala new file mode 100644 index 00000000..8c954e9e --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Hexagon.scala @@ -0,0 +1,93 @@ +package vgb.common + +import indigo.shared.datatypes.Point +import indigo.shared.datatypes.Vector2 +import indigo.shared.datatypes.Vector3 + +object Hexagon: + private val oneOver3 = 1.0 / 3.0 + private val twoOver3 = 2.0 / 3.0; + private val threeOver2 = 3.0 / 2.0; + private val sqrtThree = Math.sqrt(3) + private val sqrtThreeOver3 = sqrtThree / 3 + + def screenPosToAxial(size: Int, pos: Point) = { + val halfSize = size * 0.5; + val q = (sqrtThreeOver3 * pos.x.toDouble - oneOver3 * pos.y.toDouble) / halfSize.toDouble + val r = (twoOver3 * pos.y.toDouble) / halfSize.toDouble + + cubeToAxial( + cubeRound(axialToCube(Vector2(q, r))) + ) + } + + def screenPosToOddRow(size: Int, pos: Point) = + axialToOddRow(screenPosToAxial(size, pos)) + + def axialToScreenPos(size: Int, pos: Vector2) = + val halfSize = size * 0.5; + Point( + (halfSize * (sqrtThree * pos.x + (sqrtThree * 0.5) * pos.y)).toInt, + (halfSize * threeOver2 * pos.y).toInt + ) + + def oddRowToScreenPos(size: Int, pos: Point) = + axialToScreenPos(size, oddRowToAxial(Vector2.fromPoint(pos))) + + def axialToOddRow(pos: Vector2) = + Vector2( + pos.x + (pos.y - (pos.y.toInt & 1)) * 0.5, + pos.y + ) + + def oddRowToAxial(pos: Vector2) = + 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 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) = + Vector2(pos.x, 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) + } + + def oddRowRotate(origin: Vector2, rotationPoint: Vector2, numTurns: Byte): Vector2 = + val rotateResult = oddRowSingleRotate(origin, rotationPoint) + numTurns match + case 0 => origin + case 1 => rotateResult + case other => + oddRowRotate(rotateResult, rotationPoint, (other - 1).toByte) + + 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) = oddRowToCube(rotationPoint) match + case v => (v.x, v.y, v.z) + val (rX, rY, rZ) = + (-(originY - rotateY), -(originZ - rotateZ), -(originX - rotateX)) + + cubeToOddRow(Vector3(rX + rotateX, rY + rotateY, rZ + rotateZ)) 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..433b3717 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/Menu.scala @@ -0,0 +1,100 @@ +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; + val isEmpty: Boolean = items.isEmpty || items.exists(_ match { + case _: MenuItemTrait => true + case _ => false + }) == false + 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-common/src/vgb/common/MonsterLevel.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/MonsterLevel.scala new file mode 100644 index 00000000..cbd660f6 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/MonsterLevel.scala @@ -0,0 +1,10 @@ +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/MonsterType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/MonsterType.scala new file mode 100644 index 00000000..872fb12e --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/MonsterType.scala @@ -0,0 +1,10 @@ +package vgb.common + +import indigo.* + +enum MonsterClass: + case Normal, Boss + +enum MonsterType(val baseGame: BaseGame, val name: String, val monsterClass: MonsterClass, val bucketSize: Byte): + val assetName = AssetName(name.toLowerCase().replace(" ", "-")) + case AestherAshblade extends MonsterType(BaseGame.Gloomhaven, "Aesther Ashblade", MonsterClass.Normal, 4) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala new file mode 100644 index 00000000..994f9161 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/src/vgb/common/RoomType.scala @@ -0,0 +1,80 @@ +package vgb.common + +import indigo.* + +enum RoomType(val baseGame: BaseGame, val mapRef: String, val offset: Point, val cells: Batch[Point], val size: Size): + override def toString(): String = mapRef.capitalize + val assetName = AssetName(baseGame.shortName + "-" + mapRef) + case RoomA1A + extends RoomType( + BaseGame.Gloomhaven, + "a1a", + 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) + ) + 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) + ) +/* +{ + 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 } + ] +} + */ + +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-common/test/src/vgb/common/HexagonTests.scala b/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala new file mode 100644 index 00000000..6836f8bd --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-common/test/src/vgb/common/HexagonTests.scala @@ -0,0 +1,104 @@ +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) + ) + } + + 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/Events.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Events.scala new file mode 100644 index 00000000..d0deb43f --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Events.scala @@ -0,0 +1,10 @@ +package vgb.game + +import indigo.shared.events.GlobalEvent +import indigo.shared.datatypes.Point +import vgb.game.models.Room +import vgb.game.models.ScenarioMonster +import vgb.game.models.BoardOverlay + +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 new file mode 100644 index 00000000..7e8212a2 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/Main.scala @@ -0,0 +1,114 @@ +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.sceneModels.CreatorModel +import vgb.game.models.sceneModels.CreatorViewModel +import indigo.shared.assets.AssetType +import vgb.game.models.Room +import vgb.common.RoomType + +final case class Main(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) + extends IndigoGame[Size, Size, GameModel, GameViewModel] { + + val magnification = 1 + + def initialScene(bootData: Size): Option[SceneName] = + Some(SceneName("creator-scene")) + + 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) + .withTransparentBackground(true) + .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")) + ) + ) + .addGlobalEvents(SceneEvent.SceneChange(SceneName("creator-scene"), SceneName("creator-scene"), Seconds(0))) + + def setup( + bootData: Size, + assetCollection: AssetCollection, + dice: Dice + ): Outcome[Startup[Size]] = + Outcome(Startup.Success(bootData)) + + def initialModel(startupData: Size): Outcome[GameModel] = + Outcome( + GameModel( + startupData, + CreatorModel() + ) + ) + + def initialViewModel(startupData: Size, model: GameModel): Outcome[GameViewModel] = + Outcome( + GameViewModel( + startupData, + CreatorViewModel() + ) + ) + + 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] = + _ => Outcome(viewModel) + + def present( + context: FrameContext[Size], + model: GameModel, + viewModel: GameViewModel + ): Outcome[SceneUpdateFragment] = + Outcome(SceneUpdateFragment.empty) +} diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala new file mode 100644 index 00000000..e7caf6c4 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/BoardOverlay.scala @@ -0,0 +1,36 @@ +package vgb.game.models + +import indigo.* +import vgb.common.BoardOverlayType +import vgb.common.Hexagon +import vgb.common.RoomType + +final case class BoardOverlay( + id: Int, + overlayType: BoardOverlayType, + origin: Point, + 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)) + val worldCells = overlayType.cells.map(localToWorld) + + def rotate() = + val rotatedOrigin = + Hexagon.oddRowRotate(Vector2.fromPoint(origin), Vector2.fromPoint(rotationPoint), 1) + + this.copy( + origin = rotatedOrigin.toPoint, + 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/DragData.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/DragData.scala new file mode 100644 index 00000000..0b8cc032 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/DragData.scala @@ -0,0 +1,46 @@ +package vgb.game.models + +import indigo.* +import vgb.game.models.Room +import vgb.game.models.ScenarioMonster +import vgb.game.models.BoardOverlay +import vgb.common.Flag + +final case class DragData( + val originalPos: Point, + val pos: Point, + val dragger: Room | ScenarioMonster | BoardOverlay, + val hasMoved: Boolean +) { + def getCellMap( + map: Map[Point, Int], + rooms: Batch[Room] + ): Map[Point, Int] = + if originalPos != pos then + val cells = + dragger match { + case m: ScenarioMonster => + Batch((m.initialPosition, -Flag.Monster.value), (pos, Flag.Monster.value)) + 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: 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) => + c match { + case (point, flag) => + m.get(point) match { + case Some(f) => + if flag < 0 then + if (f & -flag) != 0 then m.updated(point, f + flag) + else m + else m.updated(point, f | flag) + case None => m + (point -> flag) + } + } + ) + else map +} 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..98996d2e --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameModel.scala @@ -0,0 +1,9 @@ +package vgb.game.models + +import indigo.* +import vgb.game.models.sceneModels.CreatorModel + +final case class GameModel(sceneModel: CreatorModel) + +object GameModel: + def apply(startupData: Size, sceneModel: CreatorModel): GameModel = GameModel(sceneModel) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala new file mode 100644 index 00000000..1f1d1d3a --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameRules.scala @@ -0,0 +1,97 @@ +package vgb.game.models + +import indigo.* +import vgb.common.* +import vgb.game.models.ScenarioMonster + +object GameRules: + def moveMonster( + newPos: Point, + monster: ScenarioMonster, + monsters: Batch[ScenarioMonster], + cellMap: Map[Point, Int] + ): Batch[ScenarioMonster] = + if (isValidMonsterPos(newPos, monster, cellMap)) + monsters.filter(m => m != monster) + :+ monster.copy(initialPosition = newPos) + else + monsters + + def moveOverlay( + newPos: Point, + overlay: BoardOverlay, + overlays: Batch[BoardOverlay], + cellMap: Map[Point, Int] + ): 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.foldLeft(0)((i, o) => Math.max(o.id, i))) + 1 else overlay.id + ) + else + overlays + + def rotateOverlay( + overlay: BoardOverlay, + overlays: Batch[BoardOverlay], + cellMap: Map[Point, Int] + ): Batch[BoardOverlay] = + val newMap = overlay.worldCells.foldLeft(cellMap)((m, c) => + m.get(c) match { + case Some(v) if (v & overlay.overlayType.flag.value) != 0 => + m.updated(c, v - overlay.overlayType.flag.value) + case _ => m + } + ) + + 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 = + val newMap = cellMap.get(monster.initialPosition) match { + case Some(v) if (v & Flag.Monster.value) != 0 => + cellMap.updated(monster.initialPosition, v - Flag.Monster.value) + case _ => cellMap + } + + newMap.get(newPos) match { + case Some(v) => (v & (Flag.Hidden.value | Flag.Monster.value)) == 0 + case None => true + } + + def isValidOverlayPos(newPos: Point, overlay: BoardOverlay, cellMap: Map[Point, Int]): Boolean = + val newMap = overlay.worldCells + .foldLeft(cellMap)((m, c) => + m.get(c) match { + case Some(v) if (v & overlay.overlayType.flag.value) != 0 => + m.updated(c, v - overlay.overlayType.flag.value) + case _ => m + } + ) + + canPlaceOverlay(overlay.copy(origin = newPos), newMap) + + def nextValidOverlayRotation( + initialRotation: TileRotation, + overlay: BoardOverlay, + cellMap: Map[Point, Int] + ): BoardOverlay = + val rotatedOverlay = overlay.rotate() + if rotatedOverlay.overlayType.flag == Flag.Coin || initialRotation == rotatedOverlay.rotation then + rotatedOverlay + else if canPlaceOverlay(rotatedOverlay, cellMap) then rotatedOverlay + else nextValidOverlayRotation(initialRotation, rotatedOverlay, cellMap) + + private def canPlaceOverlay(overlay: BoardOverlay, cellMap: Map[Point, Int]) = + overlay.worldCells + .exists(p => + cellMap.get(p) match { + case Some(v) => + // Coins can be placed anywhere except on hidden tiles + if overlay.overlayType.flag == Flag.Coin then (v & Flag.Hidden.value) != 0 + // Other overlays cannot be placed on the same squares + else (v & (Flag.Hidden.value | overlay.overlayType.flag.value)) != 0 + case None => false + } + ) == false 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..13586dd2 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/GameViewModel.scala @@ -0,0 +1,9 @@ +package vgb.game.models + +import indigo.* +import vgb.game.models.sceneModels.* + +final case class GameViewModel(sceneModel: CreatorViewModel) + +object GameViewModel: + def apply(startupData: Size, sceneModel: CreatorViewModel): GameViewModel = GameViewModel(sceneModel) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/LayerDepths.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/LayerDepths.scala new file mode 100644 index 00000000..89bbe693 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/LayerDepths.scala @@ -0,0 +1,11 @@ +package vgb.game.models + +import indigo.shared.datatypes.Depth + +object LayerDepths: + val Room = Depth(0) + val Overlay = Depth(1) + val Monster = Depth(2) + val Summons = Depth(3) + val Character = Depth(4) + val CoinOrToken = Depth(5) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala new file mode 100644 index 00000000..1d443da8 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Placeable.scala @@ -0,0 +1,59 @@ +package vgb.game.models + +import indigo.* +import vgb.common.Hexagon + +trait Placeable: + val rotation: TileRotation + val origin: Point + val minPoint: Point + val maxPoint: Point + val worldCells: Batch[Point] + lazy val rotationPoint = localToWorld( + Point((maxPoint.x * 0.5).toInt, (maxPoint.y * 0.5).toInt) + ) + + def localToWorld(localPoint: Point) = + val worldPoint = localPoint + origin + val offset = Point( + if (localPoint.y & 1) == 1 && (worldPoint.y & 1) == 0 then 1 + else 0, + 0 + ) + + 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 + ) + 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/Room.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala new file mode 100644 index 00000000..aa0d815e --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/Room.scala @@ -0,0 +1,23 @@ +package vgb.game.models + +import indigo.* +import vgb.common.Hexagon +import vgb.common.RoomType + +final case class Room( + roomType: RoomType, + origin: Point, + 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)) + val worldCells = roomType.cells.map(localToWorld) + + def rotate() = + val rotatedOrigin = + 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/ScenarioMonster.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/ScenarioMonster.scala new file mode 100644 index 00000000..a056255f --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/ScenarioMonster.scala @@ -0,0 +1,13 @@ +package vgb.game.models + +import vgb.common.MonsterType +import indigo.shared.datatypes.Point +import vgb.common.MonsterLevel + +final case class ScenarioMonster( + monsterType: MonsterType, + initialPosition: Point, + twoPlayerLevel: MonsterLevel, + threePlayerLevel: MonsterLevel, + fourPlayerLevel: MonsterLevel +) 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..728bbce3 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/TileRotation.scala @@ -0,0 +1,61 @@ +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 + } + + 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 new file mode 100644 index 00000000..0e32c108 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/BoardOverlayComponent.scala @@ -0,0 +1,135 @@ +package vgb.game.models.components + +import indigo.* +import vgb.game.models.BoardOverlay +import vgb.common.Hexagon +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 + +object BoardOverlayComponent: + def render(boardOverlay: BoardOverlay, cellMap: Map[Point, Int]): Layer = + val offset = + Hexagon.oddRowToScreenPos(HexComponent.height, Point.zero) + + Point((HexComponent.width * 0.5).toInt, (HexComponent.height * 0.5).toInt) + + val origin = + Hexagon.oddRowToScreenPos(HexComponent.height, boardOverlay.origin) + + val rotationPoint = + Hexagon.oddRowToScreenPos(HexComponent.height, boardOverlay.rotationPoint) + val newRotation = + Hexagon.oddRowToScreenPos( + HexComponent.height, + Hexagon + .oddRowRotate(Vector2.fromPoint(boardOverlay.origin), Vector2.fromPoint(boardOverlay.rotationPoint), 1) + .toPoint + ) + + (boardOverlay.overlayType match { + case Token(_, char) => + val minimise = cellMap.get(boardOverlay.origin) match { + case Some(v) if (v & Flag.MinimiseToken) != 0 => + true + case _ => false + } + val graphicGroup = Group( + Circle(Point(0, 0), (HexComponent.halfWidth * 0.75).toInt, Fill.Color(RGBA.White)), + Circle(Point(0, 0), (HexComponent.halfWidth * 0.75 * 0.9).toInt, Fill.Color(RGBA.fromHexString("#913a3d"))) + ) + val token = renderToken( + graphicGroup, + offset, + char.toString(), + RGBA.White, + false, + minimise + ).moveTo(origin) + Layer( + if minimise then + token + .moveBy(Point(HexComponent.quarterSize.toInt, -HexComponent.quarterSize.toInt)) + else token + ) + case _ => + val graphicGroup = + Graphic( + boardOverlay.overlayType match { + case _: Treasure.Coin => Size(90, 90) + case _: Door => Size(79, 90) + case _ => Size(156, 90) + }, + 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.rotation.toByte())) + Layer( + boardOverlay.overlayType match { + case t: Treasure.Coin => + val minimise = cellMap.get(boardOverlay.origin) match { + case Some(v) if (v & Flag.MinimiseCoin) != 0 => + true + case _ => false + } + val token = renderToken( + graphicGroup, + offset, + t.amount.toString(), + RGBA.fromHexString("#353535"), + true, + minimise + ).moveTo(origin) + + if minimise then + token + .moveBy(Point(HexComponent.quarterSize.toInt, HexComponent.quarterSize.toInt)) + else token + case _ => graphicGroup.moveTo(origin) + } + ) + }).withDepth(boardOverlay.overlayType match { + case t: Treasure => + t match { + case _: Treasure.Coin => LayerDepths.CoinOrToken + case _ => LayerDepths.Overlay + } + case t: Token => LayerDepths.CoinOrToken + case _ => LayerDepths.Overlay + }) + + private def renderToken( + graphic: Group | Graphic[Material.Bitmap], + hexOffset: Point, + text: String, + colour: RGBA, + addOutline: Boolean, + minimise: Boolean + ) = + val textSize = 33 + var tokenText = + TextBox(text, HexComponent.width.toInt, HexComponent.height) + .withFontFamily(FontFamily("PirateOne")) + .withFontSize(Pixels(textSize)) + .withColor(colour) + .withStroke(TextStroke(if addOutline then RGBA.White else RGBA.Zero, Pixels(2))) + .alignCenter + .withPosition(Point(-hexOffset.x, -HexComponent.quarterSize.toInt)) + if minimise then + Group( + graphic + .withScale(Vector2(0.5)), + tokenText + .withFontSize(Pixels((textSize * 0.5).toInt)) + .moveBy(0, (HexComponent.quarterSize * 0.5).toInt) + ) + else Group(graphic, tokenText) 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 new file mode 100644 index 00000000..cc4faebe --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/ContextMenuComponent.scala @@ -0,0 +1,76 @@ +package vgb.game.models.components + +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] + ): Menu = + Menu() + .add( + monster + .map(m => + Batch( + getMenuForLevel(2, m, m.twoPlayerLevel), + getMenuForLevel(3, m, m.threePlayerLevel), + getMenuForLevel(4, m, m.fourPlayerLevel) + ) + ) + .getOrElse(Batch.empty) + ) + .add( + overlays + .filter(o => + o.overlayType match { + case _: (Treasure | Token) => false + case _ => true + } + ) + .map(o => MenuItem(s"""Rotate ${o.overlayType}""", CreatorMsgType.RotateOverlay(o.id, o.overlayType))) + ) + .add(room.map(r => MenuItem(s"""Rotate ${r}""", CreatorMsgType.RotateRoom(r)))) + .add(MenuSeparator()) + .add( + monster + .map(m => + MenuItem( + s"""Remove ${m.monsterType.name}""", + CreatorMsgType.RemoveMonster(m.initialPosition, m.monsterType) + ) + ) + ) + .add( + overlays + .map(o => MenuItem(s"""Remove ${o.overlayType}""", CreatorMsgType.RemoveOverlay(o.id, o.overlayType))) + ) + .add(room.map(r => MenuItem(s"""Remove ${r}""", CreatorMsgType.RemoveRoom(r)))) + + private def getMenuForLevel(playerNum: Byte, monster: ScenarioMonster, currentLevel: MonsterLevel) = + MenuItem( + s"""${playerNum} Player State""", + Batch( + MenuItem( + "None", + CreatorMsgType.ChangeMonsterLevel(monster.initialPosition, monster.monsterType, playerNum, MonsterLevel.None) + ).withSelected(currentLevel == MonsterLevel.None), + MenuItem( + "Normal", + CreatorMsgType.ChangeMonsterLevel( + monster.initialPosition, + monster.monsterType, + playerNum, + MonsterLevel.Normal + ) + ).withSelected(currentLevel == MonsterLevel.Normal), + MenuItem( + "Elite", + CreatorMsgType.ChangeMonsterLevel(monster.initialPosition, monster.monsterType, playerNum, MonsterLevel.Elite) + ).withSelected(currentLevel == MonsterLevel.Elite) + ) + ) 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..99b2ec0c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/DragMenuComponent.scala @@ -0,0 +1,55 @@ +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.Door +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(model: CreatorModel) = + val currentRooms = model.rooms.map(r => r.roomType) + Batch( + DragDropSection( + "Tiles", + Batch( + 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( + "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/HexComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala new file mode 100644 index 00000000..b0ce262c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/HexComponent.scala @@ -0,0 +1,40 @@ +package vgb.game.models.components + +import indigo.* +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.common.Hexagon + +object HexComponent: + val height = 90 + private val sqrtThree = Math.sqrt(3) + val halfSize = height * 0.5 + val quarterSize = height * 0.25 + val width = sqrtThree * halfSize + val halfWidth = width * 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 + Point(0, -Math.floor(halfSize).toInt) // Top tip + ), + Fill.Color(RGBA.None), + Stroke.Black + ) + + 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(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), + 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/MonsterComponent.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/MonsterComponent.scala new file mode 100644 index 00000000..ebf6ce08 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/MonsterComponent.scala @@ -0,0 +1,85 @@ +package vgb.game.models.components + +import indigo.* +import indigo.shared.scenegraph.Shape.Box +import vgb.common.MonsterType +import vgb.common.Hexagon +import vgb.game.models.ScenarioMonster +import vgb.common.MonsterLevel +import indigo.shared.datatypes.Rectangle +import vgb.game.models.LayerDepths +import vgb.common.Flag + +object MonsterComponent: + val actualImageSize = Size(180, 180) + val borderAsset = AssetName("hex-border") + def render(monster: MonsterType): Graphic[Material.Bitmap] = + Graphic(actualImageSize, Material.Bitmap(monster.assetName)) + .withRef((actualImageSize / 2).toPoint) + .scaleBy(Vector2(HexComponent.height.toDouble / actualImageSize.height.toDouble)) + + def render(monster: ScenarioMonster, cellMap: Map[Point, Int]): Layer = + val origin = + Hexagon.oddRowToScreenPos(HexComponent.height, monster.initialPosition) + val quarterSize = Math.ceil(HexComponent.halfWidth * 0.5).toInt + val playerMarker = Box( + Rectangle( + Math.ceil(HexComponent.halfWidth).toInt, + Math.ceil(HexComponent.halfWidth).toInt + ), + Fill.None + ) + .withRef(Point(quarterSize, quarterSize)) + Layer( + Group.empty + .addChildren( + Batch( + this.render(monster.monsterType), + playerMarker + .withRotation(Radians.fromDegrees(32)) + .moveBy(Point(-Math.ceil(HexComponent.halfWidth).toInt, -Math.floor(HexComponent.quarterSize).toInt)) + .moveBy(Point(-5, -5)) + .withFill(getFillForLevel(monster.twoPlayerLevel)), + playerMarker + .withRotation(Radians.fromDegrees(60)) + .moveBy(Point(Math.ceil(HexComponent.halfWidth).toInt, -Math.floor(HexComponent.quarterSize).toInt)) + .moveBy(Point(5, -5)) + .withFill(getFillForLevel(monster.threePlayerLevel)), + playerMarker + .moveBy(Point(0, Math.ceil(HexComponent.halfSize).toInt)) + .moveBy(Point(0, 7)) + .withFill(getFillForLevel(monster.fourPlayerLevel)), + Graphic( + actualImageSize, + Material.Bitmap(borderAsset).toImageEffects.withTint(RGBA.fromHexString("#bc1717")) + ) + .withRef((actualImageSize / 2).toPoint) + .scaleBy(Vector2(HexComponent.height.toDouble / actualImageSize.height.toDouble)) + ) + ) + .withPosition(origin) + .withScale(Vector2(getScale(monster.initialPosition, cellMap))) + ).withDepth(LayerDepths.Monster) + + private def getFillForLevel(level: MonsterLevel) = + level match { + case MonsterLevel.None => Fill.Color(RGBA.Black) + case MonsterLevel.Normal => Fill.Color(RGBA.White) + case MonsterLevel.Elite => Fill.Color(RGBA.fromHexString("#d9c200")) + } + + private def getScale(pos: Point, cellMap: Map[Point, Int]): Double = + cellMap.get(pos) match { + case Some(v) => + val flags = + Flag.All + - Flag.Room.value + - Flag.Corridor.value + - Flag.Coin.value + - Flag.Token.value + - Flag.Monster.value + - Flag.Character.value + if (flags & v) == 0 then 1 + else 0.85 + case None => 1 + } 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..d96566da --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/components/RoomComponent.scala @@ -0,0 +1,52 @@ +package vgb.game.models.components + +import indigo.* +import vgb.common.Hexagon +import indigo.shared.scenegraph.Shape.Circle +import indigo.shared.scenegraph.Shape.Box +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) = + val offset = + Hexagon.oddRowToScreenPos(HexComponent.height, Point.zero) + + Point(HexComponent.width.toInt, (HexComponent.height * 0.5).toInt) - + room.roomType.offset + + val origin = + Hexagon.oddRowToScreenPos(HexComponent.height, room.origin) + + val rotationPoint = + Hexagon.oddRowToScreenPos(HexComponent.height, room.rotationPoint) + val newRotation = + Hexagon.oddRowToScreenPos( + HexComponent.height, + Hexagon.oddRowRotate(Vector2.fromPoint(room.origin), Vector2.fromPoint(room.rotationPoint), 1).toPoint + ) + + Layer( + Batch( + Graphic(room.roomType.size, Material.Bitmap(room.roomType.assetName)) + .withRef(offset) + .rotateTo(Radians.fromDegrees(60 * room.rotation.toByte())) + .moveTo(origin) + ) ++ + (if moveable then + Batch( + Graphic(Size(45, 45), Material.Bitmap(AssetName("move-icon"))) + .moveTo(origin - room.localToWorld(room.minPoint)) + .moveBy(Point(-(HexComponent.width * 0.5).toInt - 22, -(HexComponent.height * 0.5).toInt - 28)) + .enableEvents + .withEventHandler((g, e) => + e match { + case e: PointerEvent.PointerDown if g.bounds.contains(e.position + camera.position) => + Some(MoveStart(room.origin, room)) + case _ => None + } + ) + ) + else Batch.empty) + ).withDepth(LayerDepths.Room) 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 new file mode 100644 index 00000000..e18adfc1 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorModel.scala @@ -0,0 +1,70 @@ +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 + +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 + .foldLeft(batch)((b, cell) => b :+ (cell, Flag.Room.value)) + ) ++ + overlays + .foldLeft(Batch.empty[(Point, Int)])((batch, overlay) => + overlay.worldCells + .foldLeft(batch)((b, cell) => b :+ (cell, overlay.overlayType.flag.value)) + ) ++ + monsters + .foldLeft(Batch.empty[(Point, Int)])((batch, monster) => batch :+ (monster.initialPosition, Flag.Monster.value))) + .foldLeft(Map.empty)((map, d) => + d match { + case (cell, value) => + map.get(cell) match { + case Some(existingVal) => map.updated(cell, value | existingVal) + case None => map + (cell -> value) + } + } + ) + + override def toString(): String = + CreatorStorage.fromModel(this).asJson.deepDropNullValues.noSpaces +} + +object CreatorModel: + def apply(): CreatorModel = + CreatorModel( + "", + BaseGame.Gloomhaven, + Batch.empty, + Batch.empty, + 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() + case Left(err) => Left(err.getMessage()) + } 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 new file mode 100644 index 00000000..4790902c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/sceneModels/CreatorViewModel.scala @@ -0,0 +1,17 @@ +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( + initialDragger: Option[RoomType | BoardOverlayType | MonsterType], + dragging: Option[DragData] +) { + val camera = Camera.Fixed(Point(-200, -200)) +} + +object CreatorViewModel: + def apply(): CreatorViewModel = CreatorViewModel(None, None) 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..b5ef4185 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/CreatorStorage.scala @@ -0,0 +1,62 @@ +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, + baseGame: Option[String], + 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, + 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/DoorStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala new file mode 100644 index 00000000..b797d2f0 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/DoorStorage.scala @@ -0,0 +1,100 @@ +package vgb.game.models.storage + +import indigo.* +import vgb.game.models.Room +import vgb.common.RoomType +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, + material: Option[String], + size: Option[Byte], + direction: String, + room1X: Int, + room1Y: Int, + 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( + 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..ec2eaa44 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/MapTileDataStorage.scala @@ -0,0 +1,126 @@ +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 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 +) + +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)) + ) +} + +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, + 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, room), 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 getDoorsForRoom(room, overlays, 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) + ) + + 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 new file mode 100644 index 00000000..db2ea27e --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/OverlayStorage.scala @@ -0,0 +1,381 @@ +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 +import vgb.game.models.GameRules.rotateOverlay +import vgb.game.models.Room + +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) + + overlay.copy(origin = minCell - minPoint) + } + + 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, + 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 + ) + + 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 => + OverlayStorageRef( + "door", + "corridor", + c.codedName, + c.cells.length.toByte, + overlay.linkedRooms.getOrElse(Batch.empty).toList.map(r => r.mapRef) + ) + case o: DifficultTerrain => OverlayStorageRef("difficult-terrain", o.codedName) + case d: Door => + OverlayStorageRef( + "door", + d.codedName, + overlay.linkedRooms.getOrElse(Batch.empty).toList.map(r => r.toString()) + ) + case h: Hazard => OverlayStorageRef("hazard", h.codedName) + case h: Highlight => OverlayStorageRef("highlight", h.colour) + case o: Obstacle => OverlayStorageRef("obstacle", o.codedName) + case r: Rift => OverlayStorageRef("rift") + case s: StartingLocation => OverlayStorageRef("starting-location") + 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.codedName) + } + +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), + 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), + None, + None, + Some(mapRefs), + None, + None, + None, + None + ) + + def apply(overlayType: String, subType: String, amount: Byte): OverlayStorageRef = + OverlayStorageRef( + overlayType, + Some(subType), + None, + None, + None, + None, + None, + None, + Some(amount) + ) + + def apply(overlayType: String, subType: String, treasureType: TreasureChestType): OverlayStorageRef = + OverlayStorageRef( + overlayType, + Some(subType), + None, + None, + None, + None, + None, + Some(treasureType.toString()), + None + ) + + def apply( + overlayType: String, + subType: String, + material: String, + size: Byte, + mapRefs: List[String] + ): OverlayStorageRef = + OverlayStorageRef( + overlayType, + Some(subType), + Some(material), + 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..18814e6c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/RoomStorage.scala @@ -0,0 +1,40 @@ +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] = + 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}""") + } +} + +final case class RoomDataStorage( + ref: String, + origin: CellStorage, + turns: Byte +) + +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..5246f862 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioMonsterStorage.scala @@ -0,0 +1,47 @@ +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, + initialX: Int, + initialY: Int, + 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) = + 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/models/storage/ScenarioStorage.scala b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala new file mode 100644 index 00000000..cd900b4c --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/models/storage/ScenarioStorage.scala @@ -0,0 +1,343 @@ +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.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 +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: + 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 => + ScenarioStorage( + model.scenarioTitle, + model.baseGame, + head, + overlays, + monsters, + Batch.fromList(tail) + ) + case _ => + ScenarioStorage( + 0, + model.scenarioTitle, + model.baseGame match { + case BaseGame.Gloomhaven => None + case _ => Some(model.baseGame.toString().toLowerCase()) + }, + None, + 0, + List.empty + ) + } + + def apply( + title: String, + baseGame: BaseGame, + startingRoom: Room, + overlays: Batch[(RoomType, BoardOverlay)], + monsters: Batch[(RoomType, ScenarioMonster)], + rooms: Batch[Room] + ): ScenarioStorage = + ScenarioStorage( + 0, + title, + baseGame match { + case BaseGame.Gloomhaven => None + case _ => Some(baseGame.toString().toLowerCase()) + }, + Some( + MapTileDataStorage( + startingRoom, + overlays, + monsters, + rooms :+ startingRoom, + rooms :+ startingRoom + )._1 + ), + 0, + 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] + ): 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 new file mode 100644 index 00000000..42799d11 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-game/src/vgb/game/scenes/CreatorScene.scala @@ -0,0 +1,421 @@ +package vgb.game.scenes + +import cats.effect.IO +import indigo.* +import indigo.scenes.* +import tyrian.TyrianSubSystem +import indigo.shared.datatypes.RGBA +import vgb.game.models.Room +import vgb.common.* +import vgb.game.models.GameModel +import vgb.game.models.GameViewModel +import vgb.game.MoveStart +import vgb.game.MoveEnd +import vgb.common.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 +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 + * + * @param tyrianSubSystem + */ +final case class CreatorScene(tyrianSubSystem: TyrianSubSystem[IO, GloomhavenMsg]) + extends Scene[Size, GameModel, GameViewModel]: + + type SceneModel = CreatorModel + type SceneViewModel = CreatorViewModel + + val name: SceneName = SceneName("creator-scene") + val saveSlot: String = "creator" + + val modelLens: Lens[GameModel, CreatorModel] = + Lens( + (gameModel: GameModel) => + gameModel.sceneModel match { + case m: CreatorModel => m + }, + (gameModel: GameModel, model: CreatorModel) => gameModel.copy(sceneModel = model) + ) + + val viewModelLens: Lens[GameViewModel, CreatorViewModel] = + Lens( + (gameViewModel: GameViewModel) => + gameViewModel.sceneModel match { + case m: CreatorViewModel => m + }, + (gameViewModel: GameViewModel, viewModel: CreatorViewModel) => gameViewModel.copy(sceneModel = viewModel) + ) + + val eventFilters: EventFilters = + EventFilters.AllowAll + + val subSystems: Set[SubSystem] = + Set() + + def updateModel( + 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))) + ) + .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 { + case o: BoardOverlay => + model.copy(overlays = GameRules.moveOverlay(newPos, o, model.overlays, model.cellMap)) + + case m: ScenarioMonster => + model.copy(monsters = GameRules.moveMonster(newPos, m, model.monsters, model.cellMap)) + + case r: Room => + model.copy(rooms = + model.rooms + .filter(room => room.roomType != r.roomType) + :+ r.copy(origin = newPos) + ) + } + + Outcome(newModel) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent + .Send(CreatorMsgType.UpdateDragMenu(DragMenuComponent.getForModel(newModel))) + ) + .addGlobalEvents(StorageEvent.Save(saveSlot, newModel.toString())) + case tyrianSubSystem.TyrianEvent.Receive(msg) => + msg match { + case msg: CreatorMsgType => + 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) + } + case _ => Outcome(model) + } + + def updateViewModel( + context: SceneContext[Size], + model: SceneModel, + viewModel: SceneViewModel + ): GlobalEvent => Outcome[SceneViewModel] = { + case MoveStart(p, d) => + viewModel.dragging match { + case None => Outcome(viewModel.copy(dragging = Some(DragData(p, p, d, false)))) + case _ => Outcome(viewModel) + } + 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, 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)) + } + + data match { + case Some(d) => Outcome(viewModel.copy(dragging = Some(DragData(pos, pos, d, false)))) + case None => Outcome(viewModel) + } + case _ => Outcome(viewModel) + } + ).addGlobalEvents( + tyrianSubSystem.TyrianEvent + .Send(GeneralMsgType.CloseContextMenu) + ) + case e: PointerEvent.PointerMove => + val pos = Hexagon.screenPosToOddRow(HexComponent.height, e.position + 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, TileRotation.Default) + case m: MonsterType => + ScenarioMonster( + m, + pos, + MonsterLevel.Normal, + MonsterLevel.Normal, + MonsterLevel.Normal + ) + case o: BoardOverlayType => BoardOverlay(0, o, pos, TileRotation.Default) + } + Some(DragData(pos, pos, item, true)) + case None => None + } + ) + draggingData match { + case Some(d) => + val isValid = d.dragger match { + 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))), + initialDragger = None + ) + ) + else Outcome(viewModel) + case None => Outcome(viewModel) + } + 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)) + .addGlobalEvents(MoveEnd(d.pos, d.dragger)) + case Some(d) if d.hasMoved => + Outcome(viewModel.copy(dragging = None)) + case _ => + val hexPos = Hexagon.screenPosToOddRow(HexComponent.height, e.position + viewModel.camera.position).toPoint + Outcome(viewModel.copy(dragging = None)) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent + .Send( + GeneralMsgType.ShowContextMenu( + 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), + model.overlays.filter(o => o.worldCells.contains(hexPos)) + ) + ) + ) + ) + } + case tyrianSubSystem.TyrianEvent.Receive(msg) => + updateViewModelFromTyrian(context, viewModel, msg) + case _ => + Outcome(viewModel) + } + + def present( + context: SceneContext[Size], + model: SceneModel, + viewModel: SceneViewModel + ): Outcome[SceneUpdateFragment] = + val cellMap = viewModel.dragging + .map(d => d.getCellMap(model.cellMap, model.rooms)) + .getOrElse(model.cellMap) + + Outcome( + SceneUpdateFragment.empty + .addLayers( + model.rooms + .filter(r => + viewModel.dragging match { + case Some(d) if d.originalPos != d.pos => + d.dragger match { + case r1: Room => r1.roomType != r.roomType + case _ => true + } + case _ => true + } + ) + .map(r => RoomComponent.render(r, viewModel.camera, true)) + ) + .addLayers( + model.monsters + .filter(m => + viewModel.dragging match { + case Some(d) if d.originalPos != d.pos => + d.dragger match { + case m1: ScenarioMonster => m1 != m + case _ => true + } + case _ => true + } + ) + .map(m => MonsterComponent.render(m, cellMap)) + ) + .addLayers( + model.overlays + .filter(o => + viewModel.dragging match { + case Some(d) if d.originalPos != d.pos => + d.dragger match { + case o1: BoardOverlay => o1.id != o.id + case _ => true + } + case _ => true + } + ) + .map(o => BoardOverlayComponent.render(o, cellMap)) + ) + .addLayer( + viewModel.dragging match { + case Some(d) if d.originalPos != d.pos => + d.dragger match { + case m: ScenarioMonster => + MonsterComponent.render(m.copy(initialPosition = d.pos), cellMap) + case o: BoardOverlay => + 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) + ) + + def updateModelFromTyrian( + context: SceneContext[Size], + model: SceneModel, + msg: CreatorMsgType + ): Outcome[SceneModel] = + 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) => + val newMonster = m.copy( + twoPlayerLevel = if playerNum == 2 then level else m.twoPlayerLevel, + threePlayerLevel = if playerNum == 3 then level else m.threePlayerLevel, + fourPlayerLevel = if playerNum == 4 then level else m.fourPlayerLevel + ) + + Outcome(model.copy(monsters = model.monsters.map(m1 => if m1 == m then newMonster else m1))) + case _ => Outcome(model) + } + case CreatorMsgType.RemoveMonster(p, m) => + Outcome(model.copy(monsters = model.monsters.filterNot(m1 => p == m1.initialPosition && m == m1.monsterType))) + case CreatorMsgType.RemoveOverlay(id, o) => + Outcome(model.copy(overlays = model.overlays.filterNot(o1 => id == o1.id && o == o1.overlayType))) + case CreatorMsgType.RotateOverlay(id, o) => + model.overlays.find(o1 => id == o1.id && o == o1.overlayType) match { + case Some(overlay) => + Outcome( + model.copy(overlays = GameRules.rotateOverlay(overlay, model.overlays, model.cellMap)) + ) + case None => Outcome(model) + } + case CreatorMsgType.RemoveRoom(r) => + Outcome(model.copy(rooms = model.rooms.filterNot(r1 => r == r1.roomType))) + case CreatorMsgType.RotateRoom(r) => + model.rooms.find(r1 => r1.roomType == r) match { + case Some(room) => + val rotatedOrigin = + Hexagon.oddRowRotate(Vector2.fromPoint(room.origin), Vector2.fromPoint(room.rotationPoint), 1) + val newRoom = room.copy( + origin = rotatedOrigin.toPoint, + rotation = room.rotation.nextRotation(false) + ) + Outcome(model.copy(rooms = model.rooms.map(r1 => if r1 == room then newRoom else r1))) + case None => Outcome(model) + } + case CreatorMsgType.ExportFile => + Outcome(model) + .addGlobalEvents( + tyrianSubSystem.TyrianEvent.Send( + CreatorMsgType.ExportFileString( + model.scenarioTitle, + ScenarioStorage.fromModel(model).toString() + ) + ) + ) + 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) + } + + 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-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/Main.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala new file mode 100644 index 00000000..879c9013 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Main.scala @@ -0,0 +1,277 @@ +package vgb.ui + +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 +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 + case RetryIndigo + case IndigoReceive(msg: GloomhavenMsg) + case IndigoSend(msg: GloomhavenMsg) + case StartIndigo + case OpenContextItem(itemId: Byte) + 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]: + 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)) + + 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 => + 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.1.seconds)) + case Msg.CloseContextMenu => + ( + model.copy(sceneModel = model.sceneModel.updateContextMenu(None)), + Cmd.None + ) + case Msg.OpenContextItem(i) => + model.sceneModel.contextMenu match { + case Some((p, menu)) => + 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 + ) + case None => (model, Cmd.None) + } + case Msg.NoOp => (model, Cmd.None) + case Msg.ToggleMainMenu => + ( + 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) + + 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) + ), + div(`class` := "main", attribute("aria-label", "Gloomhaven board layout"))( + 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")()) + } + ) + ), + footer( + div(`class` := "credits")( + span(`class` := "gloomCopy")( + text("Gloomhaven and all related properties and images are owned by "), + a(href := "http://www.cephalofair.com/")("Cephalofair Games") + ), + span(`class` := "any2CardCopy")( + text("Additional card scans courtesy of "), + a(href := "https://github.com/any2cards/worldhaven")("Any2Cards") + ) + ), + div(`class` := "pkg")( + 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") + )() + ), + a( + target := "_new", + href := "https://github.com/PurpleKingdomGames/virtual-gloomhaven-board/issues/new/choose" + )("Report a bug"), + span(s"""Version ${appVersion}""") + ) + ) + ) + + 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, model.sceneModel) match { + case (msg: GeneralMsgType, _) => + msg match { + case GeneralMsgType.ShowContextMenu(p, m) => + val someMenu = + if m.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(someMenu)), + Cmd.None + ) + 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)) + (model.copy(sceneModel = sceneModel), cmd.map(Msg.IndigoSend(_))) + } + + def updateContextMenuItem( + items: Batch[MenuItemTrait | MenuSeparator], + idToFind: Byte, + opened: Boolean + ): Batch[MenuItemTrait | MenuSeparator] = + items + .map(item => + item match { + case i: MenuItem => + i.copy( + open = (i.id == idToFind) && opened, + subItems = updateContextMenuItem(i.subItems, idToFind, opened) + ) + case _ => item + } + ) + + @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/Model.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Model.scala new file mode 100644 index 00000000..a9c79dfc --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/Model.scala @@ -0,0 +1,28 @@ +package vgb.ui + +import cats.effect.IO +import tyrian.TyrianIndigoBridge +import vgb.common.GloomhavenMsg +import vgb.ui.scenes.* +import vgb.ui.models.UiModel + +/** Represents a model for the application + * + * @param bridge + * The bridge between Indigo and Tyrian + */ +final case class Model( + bridge: TyrianIndigoBridge[IO, GloomhavenMsg], + indigoStarted: Boolean, + sceneModel: UiModel, + scene: TyrianScene +) + +object Model: + def apply(): Model = + Model( + TyrianIndigoBridge(), + false, + CreatorModel(), + CreatorScene + ) diff --git a/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/UiModel.scala b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/UiModel.scala new file mode 100644 index 00000000..0bf074e2 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/UiModel.scala @@ -0,0 +1,11 @@ +package vgb.ui.models + +import indigo.shared.datatypes.Point +import vgb.common.Menu + +trait 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 new file mode 100644 index 00000000..6a8e26b3 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/ContextMenuComponent.scala @@ -0,0 +1,43 @@ +package vgb.ui.models.components + +import indigo.shared.datatypes.Point +import indigo.shared.collections.Batch +import indigo.* +import vgb.common.Menu +import vgb.common.MenuItem +import vgb.common.MenuSeparator +import tyrian.* +import tyrian.Html.* +import vgb.ui.Msg + +object ContextMenuComponent: + def render(pos: Point, menu: Menu): Html[Msg] = + val hasItems = menu.isEmpty == false + 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( + ("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"), + ("style", s"""top: ${pos.y}px; left: ${pos.x}px""") + ) + )( + if hasItems then MenuComponent.render(menu, hasItems) + else Empty + ) 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..87ba1928 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/models/components/MenuComponent.scala @@ -0,0 +1,115 @@ +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 +import vgb.common.GeneralMsgType + +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(m: GeneralMsgType.ShowImportDialog) => Msg.IndigoReceive(m) + 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 new file mode 100644 index 00000000..1348d205 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/CreatorScene.scala @@ -0,0 +1,144 @@ +package vgb.ui.scenes + +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 +import vgb.common.Menu +import vgb.ui.Model +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 +import org.scalajs.dom +import indigo.shared.IndigoLogger +import scala.util.matching.Regex +import java.util.Base64 + +object CreatorScene extends TyrianScene { + type SceneModel = CreatorModel + + def getModel(model: Model): CreatorModel = + model.sceneModel match { + case m: CreatorModel => m + case _ => CreatorModel() + } + + def update(msg: vgb.common.GloomhavenMsg, model: CreatorModel): (CreatorModel, Cmd[IO, GloomhavenMsg]) = + msg match { + 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 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)) + + case _ => + (model, Cmd.None) + } + + 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, + value := model.scenarioTitle, + onInput(_ match { + case t => Msg.IndigoSend(CreatorMsgType.ChangeScenarioTitle(t)) + }) + ) + ) + ) + ) + + def getBoardAdditions(model: CreatorModel): List[Html[Msg]] = List( + div(`class` := "page-shadow")(), + 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.name + case r: RoomType => s"""Map tile ${i.item.toString()}""" + } + ) + ) + .toList + ) + ) + ) + .toList + ) + ) +} + +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 = + this.copy(contextMenu = menu) + def toggleMainMenu(): UiModel = + this.copy(showMainMenu = showMainMenu != true) +} + +object CreatorModel: + def apply(): CreatorModel = CreatorModel( + "", + Menu() + .add(Some(MenuItem("Create New", CreatorMsgType.CreateNewScenario))) + .add(MenuSeparator()) + .add(Some(MenuItem("Export", CreatorMsgType.ExportFile))) + .add(Some(MenuItem("Import", GeneralMsgType.ShowImportDialog(CreatorMsgType.ImportFile.apply)))) + .add(MenuSeparator()), + false, + Batch.empty, + "", + 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 new file mode 100644 index 00000000..620e617b --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/vgb-ui/src/vgb/ui/scenes/TyrianScene.scala @@ -0,0 +1,17 @@ +package vgb.ui.scenes + +import cats.effect.IO +import tyrian.Cmd +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 getBoardAdditions(model: SceneModel): List[Html[Msg]] + def getHeader(model: SceneModel): List[Html[Msg]] diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/index.html b/VirtualGloomhavenBoard/Indigo/wwwroot/index.html new file mode 100644 index 00000000..081621d9 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/index.html @@ -0,0 +1,47 @@ + + + + + + + + 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..957f3792 --- /dev/null +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/js/app.js @@ -0,0 +1,247 @@ +//require('@microsoft/signalr') +import * as t from '../../out/vgb-ui/fastLinkJS.dest/main.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/scss/_context-menu.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss similarity index 95% rename from VirtualGloomhavenBoard/assets/scss/_context-menu.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss index e8cee61f..506b215b 100644 --- a/VirtualGloomhavenBoard/assets/scss/_context-menu.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_context-menu.scss @@ -1,6 +1,6 @@ .context-menu { position: absolute; - border-image: url('/img/border.png') 0 fill; + border-image: url('../static/img/border.webp') 0 fill; background-color: transparent; border-style: solid; padding: 1.4rem; @@ -26,6 +26,7 @@ padding: 0.2rem 1rem; border-radius: 0.2rem; position: relative; + user-select: none; &:hover { cursor: pointer; @@ -45,7 +46,7 @@ visibility: hidden; position: absolute; right: -7.1rem; - border-image: url('/img/border.png') 0 fill; + border-image: url('../static/img/border.webp') 0 fill; background-color: transparent; border-style: solid; padding: 1.4rem; @@ -111,4 +112,4 @@ } } } -} \ No newline at end of file +} diff --git a/VirtualGloomhavenBoard/assets/scss/_creator.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss similarity index 57% rename from VirtualGloomhavenBoard/assets/scss/_creator.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss index a6232999..4cf5d908 100644 --- a/VirtualGloomhavenBoard/assets/scss/_creator.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_creator.scss @@ -1,7 +1,6 @@ @use 'mixins'; -html -{ +html { .content.scenario-creator { header { .title { @@ -26,12 +25,13 @@ html } } } + .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); + -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; @@ -45,7 +45,7 @@ html justify-content: flex-start; padding-bottom: 1rem; width: 10.5rem; - @include mixins.mask(url('/img/page-mask.png'), alpha, top right); + @include mixins.mask(url('../static/img/page-mask.webp'), alpha, top right); @include mixins.mask-repeat(repeat-y); section { @@ -59,7 +59,7 @@ html header { flex-basis: 1rem; padding: 0.2rem 0 0.75rem 1rem; - background-image: url('/img/accordian-banner.png'); + background-image: url('../static/img/accordian-banner.webp'); background-repeat: no-repeat; background-size: cover; background-position-y: -0.5rem; @@ -71,9 +71,9 @@ html 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); + -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; } @@ -89,14 +89,16 @@ html 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); + -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; + user-select: none; + -webkit-user-select: none; img { max-width: 45px; @@ -112,7 +114,8 @@ html img { position: relative; - &:first-child, &:nth-child(2) { + &:first-child, + &:nth-child(2) { top: 31px; } @@ -167,115 +170,6 @@ html } } } - - .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/Indigo/wwwroot/scss/_form.scss similarity index 84% rename from VirtualGloomhavenBoard/assets/scss/_form.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_form.scss index 1c7b66d1..af0245a6 100644 --- a/VirtualGloomhavenBoard/assets/scss/_form.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_form.scss @@ -17,14 +17,14 @@ padding: 0.4rem; font-size: 1.1rem; outline: none; - background-color: rgba(49,40,38, 0.7); + 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); + -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); } } @@ -64,7 +64,7 @@ top: 0.1rem; right: 0; box-sizing: content-box; - background-image: url('/img/icons.png'); + background-image: url('../static/img/icons.webp'); background-size: 128px; background-position: -72px -24px; transform: scale(1.4); @@ -116,14 +116,14 @@ padding: 0.4rem; font-size: 1.1rem; outline: none; - background-color: rgba(49,40,38, 0.7); + 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); + -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); } } } @@ -144,4 +144,4 @@ color: #93292e; font-family: "PirateOne", Nyala, Georgia, serif; } -} \ No newline at end of file +} diff --git a/VirtualGloomhavenBoard/assets/scss/_icons.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_icons.scss similarity index 96% rename from VirtualGloomhavenBoard/assets/scss/_icons.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_icons.scss index 813bd5e9..b66c59b8 100644 --- a/VirtualGloomhavenBoard/assets/scss/_icons.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_icons.scss @@ -11,7 +11,7 @@ i { display: block; width: 45px; height: 45px; - background-image: url("/img/characters/icons.png"); + background-image: url("../static/img/characters/icons.webp"); background-size: 256px; filter: contrast(0%) brightness(130%) drop-shadow(1px 1px black); top: 0.7rem; @@ -91,4 +91,4 @@ i { background-position: 0 -90px; } } -} \ No newline at end of file +} diff --git a/VirtualGloomhavenBoard/assets/scss/_layout.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss similarity index 87% rename from VirtualGloomhavenBoard/assets/scss/_layout.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss index a51d2482..87083144 100644 --- a/VirtualGloomhavenBoard/assets/scss/_layout.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_layout.scss @@ -2,8 +2,8 @@ @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'); + 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 { @@ -55,7 +55,7 @@ html { .header { position: absolute; display: flex; - background-image: url('/img/plank.jpg'); + background-image: url('../static/img/plank.webp'); border-bottom: 1px solid black; box-shadow: 0 5px 40px 0 black; background-size: contain; @@ -78,7 +78,7 @@ html { display: block; width: 45px; height: 45px; - background-image: url("/img/icons.png"); + background-image: url("../static/img/icons.webp"); background-size: 256px; background-position: -90px -45px; filter: invert(100%) drop-shadow(2px 1px 0 black); @@ -92,7 +92,7 @@ html { opacity: 0; visibility: hidden; transition: 0.3s; - background-image: url('/img/plank.jpg'); + background-image: url('../static/img/plank.webp'); border: 2px solid #222; background-size: 190%; top: 4rem; @@ -115,7 +115,7 @@ html { left: 0.7rem; height: 0.3rem; top: -0.5rem; - background-image: url("/img/plank.jpg"); + background-image: url("../static/img/plank.webp"); } ul { @@ -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; @@ -257,7 +268,7 @@ html { display: flex; position: absolute; overflow: visible; - background-image: url("/img/bg.jpg"); + background-image: url("../static/img/bg.webp"); box-shadow: 10px 0px 40px 10px rgba(0, 0, 0, 0.75); z-index: 2; left: 0; @@ -271,7 +282,7 @@ html { top: 50vh; right: -2.5rem; bottom: 50vh; - background-image: url('/img/plank.jpg'); + background-image: url('../static/img/plank.webp'); display: none; transition: right 0.5s; @@ -305,10 +316,10 @@ html { width: 110px; height: 100%; overflow: hidden; - background-image: url("/img/bg.jpg"); + background-image: url("../static/img/bg.webp"); background-repeat: repeat; background-attachment: local; - @include mixins.mask(url('/img/page-mask.png'), alpha, top right); + @include mixins.mask(url('../static/img/page-mask.webp'), alpha, top right); @include mixins.mask-repeat(repeat-y); ul { @@ -325,7 +336,7 @@ html { display: inline-block; padding: 5px 10px; transition: all 0.25s; - background-image: url('/img/icons.png'); + background-image: url('../static/img/icons.webp'); font-size: 0; text-indent: -9999rem; width: 45px; @@ -402,10 +413,10 @@ html { .new-piece-list { height: 100%; width: 140px; - @include mixins.mask(url('/img/page-mask.png'), alpha, bottom right); + @include mixins.mask(url('../static/img/page-mask.webp'), alpha, bottom right); @include mixins.mask-repeat(repeat-y); padding-right: 16px; - background-image: url("/img/bg.jpg"); + background-image: url("../static/img/bg.webp"); background-repeat: repeat; background-attachment: local; @@ -417,7 +428,7 @@ html { height: 100%; overflow: hidden; overflow-x: hidden; - background-image: url("/img/bg.jpg"); + background-image: url("../static/img/bg.webp"); background-repeat: repeat; background-attachment: local; scrollbar-width: thin; @@ -444,21 +455,16 @@ html { 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-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('/img/compass.png'); - width: 175px; - height: 254px; - opacity: 0.55; + canvas { + position: relative; + z-index: 1; } } @@ -531,7 +537,7 @@ html { 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-image: url("../static/img/plank.webp"); background-size: contain; border-top: 1px solid black; box-shadow: 0 -5px 40px 0 black; @@ -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; + } } } @@ -632,4 +631,4 @@ html { } } } -} \ No newline at end of file +} diff --git a/VirtualGloomhavenBoard/assets/scss/_mixins.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_mixins.scss similarity index 100% rename from VirtualGloomhavenBoard/assets/scss/_mixins.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_mixins.scss diff --git a/VirtualGloomhavenBoard/assets/scss/_modal.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_modal.scss similarity index 96% rename from VirtualGloomhavenBoard/assets/scss/_modal.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_modal.scss index e9305e11..49dee43e 100644 --- a/VirtualGloomhavenBoard/assets/scss/_modal.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_modal.scss @@ -2,7 +2,7 @@ position: fixed; top: 0; left: 0; - background-color: rgba(0,0,0, 0.5); + background-color: rgba(0, 0, 0, 0.5); width: 100vw; height: 100vh; display: flex; @@ -18,7 +18,7 @@ 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; + border-image: url('../static/img/border.webp') 0 fill; background-color: transparent; border-style: solid; transform: scaleX(0); @@ -78,7 +78,7 @@ text-indent: -99999em; width: 90px; height: 90px; - background-image: url('/img/characters/icons.png'); + background-image: url('../static/img/characters/icons.webp'); background-size: 512px; filter: contrast(0%) brightness(70%); transition: filter 0.25s, transform 0.15s; @@ -211,4 +211,4 @@ to { transform: scale(1); } -} \ No newline at end of file +} diff --git a/VirtualGloomhavenBoard/assets/scss/_screens.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss similarity index 92% rename from VirtualGloomhavenBoard/assets/scss/_screens.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss index 0d262bf3..4ae348f3 100644 --- a/VirtualGloomhavenBoard/assets/scss/_screens.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_screens.scss @@ -1,8 +1,8 @@ -@media - // Extra small devices (portrait phones, less than 576px) - (max-width: 575px), - // Small devices (landscape phones, 576px and up) - (max-width: 767px) { +@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; } @@ -93,14 +93,15 @@ display: none; } - .mapTiles, .board { + .mapTiles, + .board { transform: scale(0.8); transform-origin: top; } } .action-list.show { - & + .board-wrapper { + &+.board-wrapper { margin-left: 9.2rem; } } @@ -117,7 +118,9 @@ } .context-menu { - &, li ul { + + &, + li ul { width: 110%; height: 110%; position: absolute; @@ -175,13 +178,13 @@ 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"); + 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 { + &>div { width: 100%; } @@ -197,12 +200,26 @@ } } } - } +} // Medium devices (tablets, 768px and up) @media (max-width: 991px) { + html { + .content { + footer { + font-size: 0.8rem; + .pkg { + padding-top: 1rem; + + .pkgCopy { + line-height: 0.9rem; + } + } + } + } + } } // 4k+ diff --git a/VirtualGloomhavenBoard/assets/scss/_tooltip.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tooltip.scss similarity index 100% rename from VirtualGloomhavenBoard/assets/scss/_tooltip.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tooltip.scss diff --git a/VirtualGloomhavenBoard/assets/scss/_tutorial.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tutorial.scss similarity index 95% rename from VirtualGloomhavenBoard/assets/scss/_tutorial.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tutorial.scss index 2329b6cb..13671923 100644 --- a/VirtualGloomhavenBoard/assets/scss/_tutorial.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/_tutorial.scss @@ -2,7 +2,7 @@ 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"); + 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; @@ -30,4 +30,4 @@ margin-top: 1rem; justify-content: end; } -} \ No newline at end of file +} diff --git a/VirtualGloomhavenBoard/assets/scss/main.scss b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/main.scss similarity index 80% rename from VirtualGloomhavenBoard/assets/scss/main.scss rename to VirtualGloomhavenBoard/Indigo/wwwroot/scss/main.scss index 38707dbf..e5af479a 100644 --- a/VirtualGloomhavenBoard/assets/scss/main.scss +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/scss/main.scss @@ -1,11 +1,9 @@ -@use 'layout'; +@use 'layout'; @use 'form'; @use 'modal'; @use 'context-menu'; @use 'tooltip'; @use 'tutorial'; -@use 'board'; @use 'creator'; @use 'icons'; @use 'screens'; - diff --git a/VirtualGloomhavenBoard/assets/browserconfig.xml b/VirtualGloomhavenBoard/Indigo/wwwroot/static/browserconfig.xml similarity index 91% rename from VirtualGloomhavenBoard/assets/browserconfig.xml rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/browserconfig.xml index 417398a5..02e71754 100644 --- a/VirtualGloomhavenBoard/assets/browserconfig.xml +++ b/VirtualGloomhavenBoard/Indigo/wwwroot/static/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/static/fonts/PirataOne-Gloomhaven.eot similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.eot rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.eot diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.otf b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.otf similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.otf rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.otf diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.svg b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.svg similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.svg rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.svg diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.ttf b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.ttf similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.ttf rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.ttf diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.woff b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.woff similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.woff rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.woff diff --git a/VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.woff2 b/VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.woff2 similarity index 100% rename from VirtualGloomhavenBoard/assets/fonts/PirataOne-Gloomhaven.woff2 rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/fonts/PirataOne-Gloomhaven.woff2 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 00000000..cf234912 Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/accordian-banner.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/bg.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/bg.webp new file mode 100644 index 00000000..a216af4f Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/bg.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/border.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/border.webp new file mode 100644 index 00000000..3849867a Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/border.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/characters/icons.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/characters/icons.webp new file mode 100644 index 00000000..318a5f52 Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/characters/icons.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/compass.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/compass.webp new file mode 100644 index 00000000..be12e23e Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/compass.webp differ diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-144x144.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-192x192.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-192x192.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-192x192.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-192x192.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-36x36.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-36x36.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-36x36.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-36x36.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-48x48.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-48x48.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-48x48.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-48x48.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-72x72.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-72x72.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-72x72.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-72x72.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/android-icon-96x96.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-96x96.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/android-icon-96x96.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/android-icon-96x96.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/app.ico b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/app.ico similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/app.ico rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/app.ico diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-114x114.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-114x114.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-114x114.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-114x114.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-120x120.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-120x120.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-120x120.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-120x120.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-144x144.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-152x152.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-152x152.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-152x152.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-152x152.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-180x180.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-180x180.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-180x180.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-180x180.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-57x57.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-57x57.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-57x57.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-57x57.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-60x60.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-60x60.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-60x60.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-60x60.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-72x72.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-72x72.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-72x72.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-72x72.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-76x76.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-76x76.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-76x76.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-76x76.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon-precomposed.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-precomposed.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon-precomposed.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon-precomposed.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/apple-icon.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/apple-icon.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/apple-icon.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/favicon-16x16.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-16x16.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/favicon-16x16.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-16x16.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/favicon-32x32.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-32x32.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/favicon-32x32.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-32x32.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/favicon-96x96.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-96x96.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/favicon-96x96.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon-96x96.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/favicon.ico b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon.ico similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/favicon.ico rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/favicon.ico diff --git a/VirtualGloomhavenBoard/assets/img/favicons/ms-icon-144x144.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-144x144.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/ms-icon-144x144.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-144x144.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/ms-icon-150x150.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-150x150.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/ms-icon-150x150.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-150x150.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/ms-icon-310x310.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-310x310.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/favicons/ms-icon-310x310.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-310x310.png diff --git a/VirtualGloomhavenBoard/assets/img/favicons/ms-icon-70x70.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/favicons/ms-icon-70x70.png similarity index 100% rename from VirtualGloomhavenBoard/assets/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/hex-border.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/hex-border.webp new file mode 100644 index 00000000..9389f6a6 Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/hex-border.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/icons.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/icons.webp new file mode 100644 index 00000000..50687cef Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/icons.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1a.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1a.webp new file mode 100644 index 00000000..797a5c8f Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1a.webp differ 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 00000000..797a5c8f Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/map-tiles/gloomhaven/a1b.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/monsters/aesther-ashblade.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/monsters/aesther-ashblade.webp new file mode 100644 index 00000000..27fa8647 Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/monsters/aesther-ashblade.webp differ 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 00000000..6131a83e Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/move-icon.webp differ 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 00000000..6bd816cd Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/door-altar.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/obstacle-boulder-2.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/obstacle-boulder-2.webp new file mode 100644 index 00000000..f076cc33 Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/obstacle-boulder-2.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/obstacle-boulder-3.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/obstacle-boulder-3.webp new file mode 100644 index 00000000..8567ef86 Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/obstacle-boulder-3.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/treasure-coin.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/treasure-coin.webp new file mode 100644 index 00000000..c0e8d51d Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/overlays/treasure-coin.webp differ diff --git a/VirtualGloomhavenBoard/assets/img/page-mask.png b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/page-mask.png similarity index 100% rename from VirtualGloomhavenBoard/assets/img/page-mask.png rename to VirtualGloomhavenBoard/Indigo/wwwroot/static/img/page-mask.png diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/page-mask.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/page-mask.webp new file mode 100644 index 00000000..636d3b59 Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/page-mask.webp differ diff --git a/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/plank.webp b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/plank.webp new file mode 100644 index 00000000..7190cdef Binary files /dev/null and b/VirtualGloomhavenBoard/Indigo/wwwroot/static/img/plank.webp differ 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 new file mode 100644 index 00000000..04cff8c3 --- /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.30001482" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001482.tgz#8b3fad73dc35b2674a5c96df2d4f9f1c561435de" + integrity sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ== + +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.385" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.385.tgz#1afd8d6280d510145148777b899ff481c65531ff" + integrity sha512-L9zlje9bIw0h+CwPQumiuVlfMcV4boxRjFIWDcLfFqTZNbkwOExBzfmswytHawObQX4OUhtNv8gIiB21kOurIg== + +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.2: + 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.9.1" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.9.1.tgz#4375d705232b721bedb44a3993e7aa8a6f959502" + integrity sha512-jJdrNH8tzfCtT0rjPFryBXjRDQE7rqfLkah4/8B4gYa7NNZYFBcGxqWBtfQpGC+oYyBwlkj3fARk4aooKNPHxg== + optionalDependencies: + msgpackr-extract "^3.0.2" + +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== diff --git a/VirtualGloomhavenBoard/assets/img/accordian-banner.png b/VirtualGloomhavenBoard/assets/img/accordian-banner.png deleted file mode 100644 index 20fc8c2e..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/accordian-banner.png and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/img/bg.jpg b/VirtualGloomhavenBoard/assets/img/bg.jpg deleted file mode 100644 index 84743144..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/bg.jpg and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/img/border.png b/VirtualGloomhavenBoard/assets/img/border.png deleted file mode 100644 index 9f89b0f5..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/border.png and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/img/characters/icons.png b/VirtualGloomhavenBoard/assets/img/characters/icons.png deleted file mode 100644 index e08f1107..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/characters/icons.png and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/img/compass.png b/VirtualGloomhavenBoard/assets/img/compass.png deleted file mode 100644 index e23316f2..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/compass.png and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/img/hex-border-mask.png b/VirtualGloomhavenBoard/assets/img/hex-border-mask.png deleted file mode 100644 index 94e74fb4..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/hex-border-mask.png and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/img/icons.png b/VirtualGloomhavenBoard/assets/img/icons.png deleted file mode 100644 index 19f809c1..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/icons.png and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/img/monsters/aesther-ashblade.png b/VirtualGloomhavenBoard/assets/img/monsters/aesther-ashblade.png deleted file mode 100644 index 14bc910f..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/monsters/aesther-ashblade.png and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/img/plank.jpg b/VirtualGloomhavenBoard/assets/img/plank.jpg deleted file mode 100644 index 68184758..00000000 Binary files a/VirtualGloomhavenBoard/assets/img/plank.jpg and /dev/null differ diff --git a/VirtualGloomhavenBoard/assets/manifest.json b/VirtualGloomhavenBoard/assets/manifest.json deleted file mode 100644 index 96980a88..00000000 --- a/VirtualGloomhavenBoard/assets/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/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/ci.sh b/ci.sh new file mode 100755 index 00000000..741b4d51 --- /dev/null +++ b/ci.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +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 .. + 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..1bdfdc44 --- /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.jdk19; + sbtWithJRE = pkgs.sbt.override { jre = jdkToUse; }; + in + { + devShells.default = pkgs.mkShell { + packages = [ + jdkToUse + sbtWithJRE + ]; + }; + } + ); +} diff --git a/tooling.html b/tooling.html new file mode 100644 index 00000000..9f25440c --- /dev/null +++ b/tooling.html @@ -0,0 +1,1668 @@ + + + + + + + + + + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + 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/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 new file mode 100644 index 00000000..481c918d --- /dev/null +++ b/ui/ui/src/vgb/BoardHtml.scala @@ -0,0 +1,1492 @@ +package vgb + +import tyrian.Html +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) + // } + + // 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 = +// 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 +// ) + + 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 +// Just _ -> +// True + +// 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 +// 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 + +// 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 +// 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 +// ) +// ) + + // 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 +// 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 +// ) +// ) + + // 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 +// 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 +// ) +// ) + + 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 +// "hidden" + +// else if passable then +// "passable" + +// 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 +// Just ( x, y ) -> +// getOverlayLabel overlay.ref ++ " at " ++ String.fromInt x ++ ", " ++ String.fromInt y + +// 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 +// 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" + + // 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 +// 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 + + // 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 +// 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 +// ) +// ] + +// 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" +// |> 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) ] +// ] +// ] +// ] + + // def formatNameString(name: String): String = { + // name + // .split("-") + // .map(s => s.slice(0, 1).toUpperCase + s.slice(1)) + // .mkString(" ") + // } + +// 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 " " + + // 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" +// , 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: String, // 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/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 diff --git a/ui/ui/src/vgb/BoardOverlay.scala b/ui/ui/src/vgb/BoardOverlay.scala new file mode 100644 index 00000000..69450b1b --- /dev/null +++ b/ui/ui/src/vgb/BoardOverlay.scala @@ -0,0 +1,459 @@ +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) + ) + } + + 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 + } + + def getBoardOverlayType(overlayName: String): Option[BoardOverlayType] = + overlayDictionary.get(overlayName) + + def getAllOverlayTypes: List[BoardOverlayType] = + overlayDictionary.values.toList + + 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.* + + overlay match { + case Door(d, _) => + d match { + case AltarDoor => + "Altar" + + case Stone => + "Stone Door" + + case Wooden => + "Wooden Door" + + case BreakableWall => + "Breakable Wall" + + case Corridor(c, _) => + c match { + case Dark => + "Dark Corridor" + + case Earth => + "Earth Corridor" + + case ManmadeStone => + "Manmade Stone Corridor" + + case NaturalStone => + "Natural Stone Corridor" + + case PressurePlate => + "Pressure Plate" + + case Wood => + "Wooden Corridor" + } + + case DarkFog => + "Dark Fog" + + case LightFog => + "Light Fog" + } + + case DifficultTerrain(d) => + d match { + case Log => + "Fallen Log" + + case Rubble => + "Rubble" + + case Stairs => + "Stairs" + + case VerticalStairs => + "Stairs" + + case Water => + "Water" + } + + case Hazard(h) => + h match { + case HotCoals => + "Hot Coals" + + case Thorns => + "Thorns" + } + + case Highlight(c) => + c.toString ++ " Highlight" + + case Obstacle(o) => + o match { + case Altar => + "Altar" + + case Barrel => + "Barrel" + + case Bookcase => + "Bookcase" + + case Boulder1 => + "Boulder" + + case Boulder2 => + "Boulder" + + case Boulder3 => + "Boulder" + + case Bush => + "Bush" + + case Cabinet => + "Cabinet" + + case Crate => + "Crate" + + case Crystal => + "Crystal" + + case DarkPit => + "Dark Pit" + + case Fountain => + "Fountain" + + case Mirror => + "Mirror" + + case Nest => + "Nest" + + case Pillar => + "Pillar" + + case RockColumn => + "Rock Column" + + case Sarcophagus => + "Sarcophagus" + + case Shelf => + "Sheelves" + + case Stalagmites => + "Stalagmites" + + case Stump => + "Tree Stump" + + case Table => + "Table" + + case Totem => + "Totem" + + case Tree3 => + "Tree" + + case WallSection => + "Wall" + } + + case Rift => + "Rift" + + case StartingLocation => + "Starting Location" + + case Trap(t) => + t match { + case BearTrap => + "Bear Trap" + + case Spike => + "Spike Trap" + + case Poison => + "Poison Trap" + } + + case Treasure(t) => + t match { + case Chest(c) => + "Treasure Chest " + ++ (c match { + case Goal => + "Goal" + + case Locked => + "(locked)" + + case NormalChest(i) => + i.toString + }) + + case Coin(i) => + i.toString + ++ (i match { + case 1 => + " Coin" + + case _ => + " Coins" + }) + } + + case Token(t) => + "Token (" ++ t ++ ")" + + case Wall(w) => + w match { + case HugeRock => + "Huge Rock Wall" + + case Iron => + "Iron Wall" + + case LargeRock => + "Large Rock Wall" + + case ObsidianGlass => + "Obsidian Glass Wall" + + case 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/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 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) diff --git a/ui/ui/src/vgb/Game.scala b/ui/ui/src/vgb/Game.scala new file mode 100644 index 00000000..0c51cef4 --- /dev/null +++ b/ui/ui/src/vgb/Game.scala @@ -0,0 +1,928 @@ +package vgb + +object Game: + + val empty: Game = + Game(emptyState, Scenario.empty, 0, Nil, Nil) + + val emptyState: GameState = + 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) + +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: 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) + +enum Expansion: + case Gloomhaven + case Solo + +final case class RoomData(ref: MapTileRef, origin: (Int, Int), turns: Int) 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/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) diff --git a/ui/ui/src/vgb/Main.scala b/ui/ui/src/vgb/Main.scala new file mode 100644 index 00000000..5e3001c2 --- /dev/null +++ b/ui/ui/src/vgb/Main.scala @@ -0,0 +1,60 @@ +package vgb + +import cats.effect.IO +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]) = + (???, Cmd.None) + + def update(model: Model): Msg => (Model, Cmd[IO, Msg]) = + _ => (model, Cmd.None) + + def view(model: Model): Html[Msg] = + div()() + + def subscriptions(model: Model): Sub[IO, Msg] = + Sub.None + + 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 + +// 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 diff --git a/ui/ui/src/vgb/Model.scala b/ui/ui/src/vgb/Model.scala new file mode 100644 index 00000000..e10170a1 --- /dev/null +++ b/ui/ui/src/vgb/Model.scala @@ -0,0 +1,196 @@ +package vgb + +import org.scalajs.dom.Element +import cats.effect.IO +import tyrian.* + +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: + + 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 + } + ) + ) + + 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)) + } 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) 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 diff --git a/ui/ui/src/vgb/Scenario.scala b/ui/ui/src/vgb/Scenario.scala new file mode 100644 index 00000000..a0b2da54 --- /dev/null +++ b/ui/ui/src/vgb/Scenario.scala @@ -0,0 +1,198 @@ +package vgb + +object Scenario: + + val empty: Scenario = + Scenario(0, "", MapTileData(MapTileRef.A1a, Nil, Nil, Nil, 0), 0, Nil) + + 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 + .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) + + 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] +) 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) + } 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" 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) + ) + + } +} diff --git a/ui/ui/test/src/vgb/SiteTests.scala b/ui/ui/test/src/vgb/SiteTests.scala new file mode 100644 index 00000000..ad56eef1 --- /dev/null +++ b/ui/ui/test/src/vgb/SiteTests.scala @@ -0,0 +1,10 @@ +package vgb + +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==