diff --git a/.all-contributorsrc b/.all-contributorsrc
new file mode 100644
index 00000000..0a5faad0
--- /dev/null
+++ b/.all-contributorsrc
@@ -0,0 +1,115 @@
+{
+ "projectName": "JavaScript-Snake",
+ "projectOwner": "patorjk",
+ "files": ["README.md"],
+ "commitType": "docs",
+ "commitConvention": "angular",
+ "contributorsPerLine": 7,
+ "contributors": [
+ {
+ "login": "patorjk",
+ "name": "patorjk",
+ "avatar_url": "https://avatars.githubusercontent.com/u/521224?v=4",
+ "profile": "http://patorjk.com/",
+ "contributions": ["code", "doc", "design", "bug", "example"]
+ },
+ {
+ "login": "ultra17",
+ "name": "ultra17",
+ "avatar_url": "https://avatars.githubusercontent.com/u/27869698?v=4",
+ "profile": "https://github.com/ultra17",
+ "contributions": ["code", "doc", "design", "bug"]
+ },
+ {
+ "login": "Rb64",
+ "name": "Rb64",
+ "avatar_url": "https://avatars.githubusercontent.com/u/91498309?v=4",
+ "profile": "https://github.com/Rb64",
+ "contributions": ["code", "bug"]
+ },
+ {
+ "login": "legoman8304",
+ "name": "Wyatt Nulton",
+ "avatar_url": "https://avatars.githubusercontent.com/u/43346988?v=4",
+ "profile": "https://github.com/legoman8304",
+ "contributions": ["code", "bug"]
+ },
+ {
+ "login": "ashishsiot",
+ "name": "Ashish Bhoir",
+ "avatar_url": "https://avatars.githubusercontent.com/u/63919950?v=4",
+ "profile": "https://github.com/ashishsiot",
+ "contributions": ["doc"]
+ },
+ {
+ "login": "dginovker",
+ "name": "Dan G",
+ "avatar_url": "https://avatars.githubusercontent.com/u/32943174?v=4",
+ "profile": "http://dginovker.github.io",
+ "contributions": ["code", "bug"]
+ },
+ {
+ "login": "Megas4ever",
+ "name": "Megas4ever",
+ "avatar_url": "https://avatars.githubusercontent.com/u/28103886?v=4",
+ "profile": "https://github.com/Megas4ever",
+ "contributions": ["code", "design"]
+ },
+ {
+ "login": "mamamia5x",
+ "name": "Bugs Bunny",
+ "avatar_url": "https://avatars.githubusercontent.com/u/57536929?v=4",
+ "profile": "https://github.com/mamamia5x",
+ "contributions": ["code", "bug"]
+ },
+ {
+ "login": "Coteh",
+ "name": "James Cote",
+ "avatar_url": "https://avatars.githubusercontent.com/u/3276350?v=4",
+ "profile": "https://www.jamescote.ca",
+ "contributions": ["code", "bug", "doc"]
+ },
+ {
+ "login": "yokesharun",
+ "name": "Arun Yokesh",
+ "avatar_url": "https://avatars.githubusercontent.com/u/12830078?v=4",
+ "profile": "http://yokesharun.github.io/",
+ "contributions": ["code", "design"]
+ },
+ {
+ "login": "GregFrench",
+ "name": "Greg French",
+ "avatar_url": "https://avatars.githubusercontent.com/u/17938510?v=4",
+ "profile": "https://github.com/GregFrench",
+ "contributions": ["code"]
+ },
+ {
+ "login": "KT360",
+ "name": "KT360",
+ "avatar_url": "https://avatars.githubusercontent.com/u/31077743?v=4",
+ "profile": "https://github.com/KT360",
+ "contributions": ["code", "design"]
+ },
+ {
+ "login": "Thusal06",
+ "name": "Thusal Ranawaka",
+ "avatar_url": "https://avatars.githubusercontent.com/u/66709891?v=4",
+ "profile": "https://thusal06.github.io/",
+ "contributions": ["code", "design"]
+ },
+ {
+ "login": "Furtano",
+ "name": "C. S.",
+ "avatar_url": "https://avatars.githubusercontent.com/u/4115133?v=4",
+ "profile": "https://github.com/Furtano",
+ "contributions": ["code", "design"]
+ },
+ {
+ "login": "akhill2606",
+ "name": "Akhil Manohar",
+ "avatar_url": "https://avatars.githubusercontent.com/u/56164681?v=4",
+ "profile": "https://github.com/akhill2606",
+ "contributions": ["code"]
+ }
+ ]
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..f78ec928
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.parcel-cache
diff --git a/.parcelrc b/.parcelrc
new file mode 100644
index 00000000..1f3df894
--- /dev/null
+++ b/.parcelrc
@@ -0,0 +1,4 @@
+{
+ "extends": ["@parcel/config-default"],
+ "reporters": ["...", "parcel-reporter-static-files-copy"]
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..7cf19bc5
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,7 @@
+Copyright © Patrick Gillespie, http://patorjk.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index 8bb716a5..0956f864 100755
--- a/README.md
+++ b/README.md
@@ -1,19 +1,121 @@
-JavaScript Snake
-By Patrick Gillespie
-License: MIT
+# JavaScript Snake Game
+
+This is a DOM-based game of Snake that I wrote in JavaScript over a decade ago. It was made to have sort of a nostalgic feel to it.
+
+## Play and Edit the Game Online!
+
+You can now play and edit the game live in codesandbox:
+
+https://codesandbox.io/s/github/patorjk/JavaScript-Snake?file=/index.html
+
+**2025: Looks like CSS inside the sandbox isn't working properly, in the game it works fine though**
+
+On first load sometimes the game frame will not load correctly and you'll need to press the refresh icon above its display panel to get the game to show.
+
+Original game is located here:
+
http://patorjk.com/games/snake
-This is a DOM-based game of Snake that I wrote in JavaScript a few years back.
+## How to use
-Other than the full screen mode demonstrated in the code, it can also be
-initialized in div tags within a page. Example:
+The index.html file should give an idea of how to use this code. However, below you can see how to initialize it into any div within a webpage.
- var mySnakeBoard = new SNAKE.Board( {
+ const mySnakeBoard = new SNAKE.Board( {
boardContainer: "game-area",
fullScreen: false,
width: 580,
height:400
});
-
-The comments are formatted a little strange because at the time I was playing
-around with YUI Doc.
\ No newline at end of file
+
+The comments within the source code are formatted a little strange because at the time I was playing around with YUI Doc which generates documentation from code. Kind of sucks that there's so much churn in the JavaScript world. However, I'm glad the rest of the code doesn't use any external libraries, as this game still works the same after over a decade.
+
+## Running
+
+Clone project, then at command line:
+
+```
+npx parcel src/index.html
+```
+
+Runs on http://localhost:1234
+
+## AI Snake
+
+If you want to control the snake via an AI algorithm see the ai-init.js and ai-example files.
+
+Essentially all you have to do is run `params.startAIGame();` when initializing and pass in a `moveSnakeWithAI` method
+which is run before the snake does each move.
+
+```js
+ moveSnakeWithAI: ({
+ grid,
+ snakeHead,
+ currentDirection,
+ isFirstGameMove,
+ setDirection,
+ }) => {
+
+ /*
+ Direction:
+ 0
+ 3 1
+ 2
+ */
+
+ // This is NOT a real hamiltonian cycle. It misses some values, I'm just including this here as an example of
+ // a look-up type table that you could do.
+ const hamiltonianCycleGrid = [
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0],
+ [0, 0, 2, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 0],
+ [0, 0, 2, 0, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0],
+ [0, 0, 2, 0, 2, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0],
+ [0, 0, 3, 0, 3, 3, 3, 3, 0, 3, 0, 3, 0, 3, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ ];
+
+ const newDirection = hamiltonianCycleGrid[snakeHead.row][snakeHead.col];
+ setDirection(newDirection);
+ },
+ onInit: (params) => {
+ params.startAIGame(); // This start an AI game
+ },
+```
+
+## Contributors
+
+Thanks goes to these people: ([emoji key](https://allcontributors.org/docs/en/emoji-key))
+
+
+
+
+
+
+
+
+
+
diff --git a/css/snake.css b/css/snake.css
deleted file mode 100755
index ad76c145..00000000
--- a/css/snake.css
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-JavaScript Snake
-By Patrick Gillespie
-http://patorjk.com/games/snake
-*/
-body {
- margin:0px;
- padding:0px;
-}
-
-#game-area {
- margin:0px;
- padding:0px;
-}
-
-#game-area:focus { outline: none; }
-
-a.snake-link, a.snake-link:link, a.snake-link:visited {
- color: #FCFC54;
-}
-
-a.snake-link:hover {
- color: #FfFf54;
-}
-
-.snake-pause-screen {
- font-family: Verdana, arial, helvetica, sans-serif;
- font-size: 14px;
- position:absolute;
- width:300px;
- height:80px;
- text-align:center;
- top:50%;
- left:50%;
- margin-top:-40px;
- margin-left:-150px;
- display:none;
- background-color:black;
- color:white;
-}
-
-.snake-panel-component {
- position: absolute;
- font-family: Verdana, arial, helvetica, sans-serif;
- font-size: 14px;
- color: #ffffff;
- text-align: center;
- background-color: #FC5454;
- padding: 8px;
- margin: 0px;
-}
-
-.snake-snakebody-block {
- margin: 0px;
- padding: 0px;
- background-color: #FF0000;
- position: absolute;
- border: 0px solid #000080;
- background-repeat: no-repeat;
-}
-
-.snake-snakebody-alive {
- background-image: url('./images/snakeblock.png');
-}
-.snake-snakebody-dead {
- background-image: url('./images/deadblock.png');
-}
-
-.snake-food-block {
- margin: 0px;
- padding: 0px;
- background-color: #FF0000;
- border: 0px solid #000080;
- position: absolute;
-}
-
-.snake-playing-field {
- margin: 0px;
- padding: 0px;
- position: absolute;
- background-color: #0000A8;
- border: 0px solid #0000A8;
-}
-
-.snake-game-container {
- margin: 0px;
- padding: 0px;
- border-width: 0px;
- border-style: none;
- zoom: 1;
- background-color: #FC5454;
- position: relative;
-}
-
-.snake-welcome-dialog {
- padding: 8px;
- margin: 0px;
- background-color: #000000;
- color: #ffffff;
- font-family: Verdana, arial, helvetica, sans-serif;
- font-size: 14px;
- position: absolute;
- top: 50%;
- left: 50%;
- width: 300px;
- /*height: 150px;*/
- margin-top: -100px;
- margin-left: -158px;
- text-align: center;
- display: block;
-}
-
-.snake-try-again-dialog {
- padding: 8px;
- margin: 0px;
- background-color: #000000;
- color: #ffffff;
- font-family: Verdana, arial, helvetica, sans-serif;
- font-size: 14px;
- position: absolute;
- top: 50%;
- left: 50%;
- width: 300px;
- height: 100px;
- margin-top: -75px;
- margin-left: -158px;
- text-align: center;
- display: none;
-}
\ No newline at end of file
diff --git a/index.htm b/index.htm
deleted file mode 100755
index 26b1e25b..00000000
--- a/index.htm
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
- JavaScript Snake
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/js/snake.js b/js/snake.js
deleted file mode 100644
index 1f00b597..00000000
--- a/js/snake.js
+++ /dev/null
@@ -1,970 +0,0 @@
-/*
-JavaScript Snake
-By Patrick Gillespie
-http://patorjk.com/games/snake
-*/
-
-/**
-* @module Snake
-* @class SNAKE
-*/
-
-var SNAKE = SNAKE || {};
-
-/**
-* @method addEventListener
-* @param {Object} obj The object to add an event listener to.
-* @param {String} event The event to listen for.
-* @param {Function} funct The function to execute when the event is triggered.
-* @param {Boolean} evtCapturing True to do event capturing, false to do event bubbling.
-*/
-
-SNAKE.addEventListener = (function() {
- if (window.addEventListener) {
- return function(obj, event, funct, evtCapturing) {
- obj.addEventListener(event, funct, evtCapturing);
- };
- } else if (window.attachEvent) {
- return function(obj, event, funct) {
- obj.attachEvent("on" + event, funct);
- };
- }
-})();
-
-/**
-* @method removeEventListener
-* @param {Object} obj The object to remove an event listener from.
-* @param {String} event The event that was listened for.
-* @param {Function} funct The function that was executed when the event is triggered.
-* @param {Boolean} evtCapturing True if event capturing was done, false otherwise.
-*/
-
-SNAKE.removeEventListener = (function() {
- if (window.removeEventListener) {
- return function(obj, event, funct, evtCapturing) {
- obj.removeEventListener(event, funct, evtCapturing);
- };
- } else if (window.detachEvent) {
- return function(obj, event, funct) {
- obj.detachEvent("on" + event, funct);
- };
- }
-})();
-
-/**
-* This class manages the snake which will reside inside of a SNAKE.Board object.
-* @class Snake
-* @constructor
-* @namespace SNAKE
-* @param {Object} config The configuration object for the class. Contains playingBoard (the SNAKE.Board that this snake resides in), startRow and startCol.
-*/
-SNAKE.Snake = SNAKE.Snake || (function() {
-
- // -------------------------------------------------------------------------
- // Private static variables and methods
- // -------------------------------------------------------------------------
-
- var instanceNumber = 0;
- var blockPool = [];
-
- var SnakeBlock = function() {
- this.elm = null;
- this.elmStyle = null;
- this.row = -1;
- this.col = -1;
- this.xPos = -1000;
- this.yPos = -1000;
- this.next = null;
- this.prev = null;
- };
-
- // this function is adapted from the example at http://greengeckodesign.com/blog/2007/07/get-highest-z-index-in-javascript.html
- function getNextHighestZIndex(myObj) {
- var highestIndex = 0,
- currentIndex = 0,
- ii;
- for (ii in myObj) {
- if (myObj[ii].elm.currentStyle){
- currentIndex = parseFloat(myObj[ii].elm.style["z-index"],10);
- }else if(window.getComputedStyle) {
- currentIndex = parseFloat(document.defaultView.getComputedStyle(myObj[ii].elm,null).getPropertyValue("z-index"),10);
- }
- if(!isNaN(currentIndex) && currentIndex > highestIndex){
- highestIndex = currentIndex;
- }
- }
- return(highestIndex+1);
- }
-
- // -------------------------------------------------------------------------
- // Contructor + public and private definitions
- // -------------------------------------------------------------------------
-
- /*
- config options:
- playingBoard - the SnakeBoard that this snake belongs too.
- startRow - The row the snake should start on.
- startCol - The column the snake should start on.
- */
- return function(config) {
-
- if (!config||!config.playingBoard) {return;}
-
- // ----- private variables -----
-
- var me = this,
- playingBoard = config.playingBoard,
- myId = instanceNumber++,
- growthIncr = 5,
- moveQueue = [], // a queue that holds the next moves of the snake
- currentDirection = 1, // 0: up, 1: left, 2: down, 3: right
- columnShift = [0, 1, 0, -1],
- rowShift = [-1, 0, 1, 0],
- xPosShift = [],
- yPosShift = [],
- snakeSpeed = 75,
- isDead = false,
- isPaused = false;
-
- // ----- public variables -----
-
- me.snakeBody = {};
- me.snakeBody["b0"] = new SnakeBlock(); // create snake head
- me.snakeBody["b0"].row = config.startRow || 1;
- me.snakeBody["b0"].col = config.startCol || 1;
- me.snakeBody["b0"].xPos = me.snakeBody["b0"].row * playingBoard.getBlockWidth();
- me.snakeBody["b0"].yPos = me.snakeBody["b0"].col * playingBoard.getBlockHeight();
- me.snakeBody["b0"].elm = createSnakeElement();
- me.snakeBody["b0"].elmStyle = me.snakeBody["b0"].elm.style;
- playingBoard.getBoardContainer().appendChild( me.snakeBody["b0"].elm );
- me.snakeBody["b0"].elm.style.left = me.snakeBody["b0"].xPos + "px";
- me.snakeBody["b0"].elm.style.top = me.snakeBody["b0"].yPos + "px";
- me.snakeBody["b0"].next = me.snakeBody["b0"];
- me.snakeBody["b0"].prev = me.snakeBody["b0"];
-
- me.snakeLength = 1;
- me.snakeHead = me.snakeBody["b0"];
- me.snakeTail = me.snakeBody["b0"];
- me.snakeHead.elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/,'');
- me.snakeHead.elm.className += " snake-snakebody-alive";
-
- // ----- private methods -----
-
- function createSnakeElement() {
- var tempNode = document.createElement("div");
- tempNode.className = "snake-snakebody-block";
- tempNode.style.left = "-1000px";
- tempNode.style.top = "-1000px";
- tempNode.style.width = playingBoard.getBlockWidth() + "px";
- tempNode.style.height = playingBoard.getBlockHeight() + "px";
- return tempNode;
- }
-
- function createBlocks(num) {
- var tempBlock;
- var tempNode = createSnakeElement();
-
- for (var ii = 1; ii < num; ii++){
- tempBlock = new SnakeBlock();
- tempBlock.elm = tempNode.cloneNode(true);
- tempBlock.elmStyle = tempBlock.elm.style;
- playingBoard.getBoardContainer().appendChild( tempBlock.elm );
- blockPool[blockPool.length] = tempBlock;
- }
-
- tempBlock = new SnakeBlock();
- tempBlock.elm = tempNode;
- playingBoard.getBoardContainer().appendChild( tempBlock.elm );
- blockPool[blockPool.length] = tempBlock;
- }
-
- // ----- public methods -----
-
- me.setPaused = function(val) {
- isPaused = val;
- };
- me.getPaused = function() {
- return isPaused;
- };
-
- /**
- * This method is called when a user presses a key. It logs arrow key presses in "moveQueue", which is used when the snake needs to make its next move.
- * @method handleArrowKeys
- * @param {Number} keyNum A number representing the key that was pressed.
- */
- /*
- Handles what happens when an arrow key is pressed.
- Direction explained (0 = up, etc etc)
- 0
- 3 1
- 2
- */
- me.handleArrowKeys = function(keyNum) {
- if (isDead || isPaused) {return;}
-
- var snakeLength = me.snakeLength;
- var lastMove = moveQueue[0] || currentDirection;
-
- //console.log("lastmove="+lastMove);
- //console.log("dir="+keyNum);
-
- switch (keyNum) {
- case 37:
- case 65:
- if ( lastMove !== 1 || snakeLength === 1 ) {
- moveQueue.unshift(3); //SnakeDirection = 3;
- }
- break;
- case 38:
- case 87:
- if ( lastMove !== 2 || snakeLength === 1 ) {
- moveQueue.unshift(0);//SnakeDirection = 0;
- }
- break;
- case 39:
- case 68:
- if ( lastMove !== 3 || snakeLength === 1 ) {
- moveQueue.unshift(1); //SnakeDirection = 1;
- }
- break;
- case 40:
- case 83:
- if ( lastMove !== 0 || snakeLength === 1 ) {
- moveQueue.unshift(2);//SnakeDirection = 2;
- }
- break;
- }
- };
-
- /**
- * This method is executed for each move of the snake. It determines where the snake will go and what will happen to it. This method needs to run quickly.
- * @method go
- */
- me.go = function() {
-
- var oldHead = me.snakeHead,
- newHead = me.snakeTail,
- myDirection = currentDirection,
- grid = playingBoard.grid; // cache grid for quicker lookup
-
- if (isPaused === true) {
- setTimeout(function(){me.go();}, snakeSpeed);
- return;
- }
-
- me.snakeTail = newHead.prev;
- me.snakeHead = newHead;
-
- // clear the old board position
- if ( grid[newHead.row] && grid[newHead.row][newHead.col] ) {
- grid[newHead.row][newHead.col] = 0;
- }
-
- if (moveQueue.length){
- myDirection = currentDirection = moveQueue.pop();
- }
-
- newHead.col = oldHead.col + columnShift[myDirection];
- newHead.row = oldHead.row + rowShift[myDirection];
- newHead.xPos = oldHead.xPos + xPosShift[myDirection];
- newHead.yPos = oldHead.yPos + yPosShift[myDirection];
-
- if ( !newHead.elmStyle ) {
- newHead.elmStyle = newHead.elm.style;
- }
-
- newHead.elmStyle.left = newHead.xPos + "px";
- newHead.elmStyle.top = newHead.yPos + "px";
-
- // check the new spot the snake moved into
-
- if (grid[newHead.row][newHead.col] === 0) {
- grid[newHead.row][newHead.col] = 1;
- setTimeout(function(){me.go();}, snakeSpeed);
- } else if (grid[newHead.row][newHead.col] > 0) {
- me.handleDeath();
- } else if (grid[newHead.row][newHead.col] === playingBoard.getGridFoodValue()) {
- grid[newHead.row][newHead.col] = 1;
- me.eatFood();
- setTimeout(function(){me.go();}, snakeSpeed);
- }
- };
-
- /**
- * This method is called when it is determined that the snake has eaten some food.
- * @method eatFood
- */
- me.eatFood = function() {
- if (blockPool.length <= growthIncr) {
- createBlocks(growthIncr*2);
- }
- var blocks = blockPool.splice(0, growthIncr);
-
- var ii = blocks.length,
- index,
- prevNode = me.snakeTail;
- while (ii--) {
- index = "b" + me.snakeLength++;
- me.snakeBody[index] = blocks[ii];
- me.snakeBody[index].prev = prevNode;
- me.snakeBody[index].elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/,'')
- me.snakeBody[index].elm.className += " snake-snakebody-alive";
- prevNode.next = me.snakeBody[index];
- prevNode = me.snakeBody[index];
- }
- me.snakeTail = me.snakeBody[index];
- me.snakeTail.next = me.snakeHead;
- me.snakeHead.prev = me.snakeTail;
-
- playingBoard.foodEaten();
- };
-
- /**
- * This method handles what happens when the snake dies.
- * @method handleDeath
- */
- me.handleDeath = function() {
- me.snakeHead.elm.style.zIndex = getNextHighestZIndex(me.snakeBody);
- me.snakeHead.elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-alive\b/,'')
- me.snakeHead.elm.className += " snake-snakebody-dead";
-
- isDead = true;
- playingBoard.handleDeath();
- moveQueue.length = 0;
- };
-
- /**
- * This method sets a flag that lets the snake be alive again.
- * @method rebirth
- */
- me.rebirth = function() {
- isDead = false;
- };
-
- /**
- * This method reset the snake so it is ready for a new game.
- * @method reset
- */
- me.reset = function() {
- if (isDead === false) {return;}
-
- var blocks = [],
- curNode = me.snakeHead.next,
- nextNode;
- while (curNode !== me.snakeHead) {
- nextNode = curNode.next;
- curNode.prev = null;
- curNode.next = null;
- blocks.push(curNode);
- curNode = nextNode;
- }
- me.snakeHead.next = me.snakeHead;
- me.snakeHead.prev = me.snakeHead;
- me.snakeTail = me.snakeHead;
- me.snakeLength = 1;
-
- for (var ii = 0; ii < blocks.length; ii++) {
- blocks[ii].elm.style.left = "-1000px";
- blocks[ii].elm.style.top = "-1000px";
- blocks[ii].elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/,'')
- blocks[ii].elm.className += " snake-snakebody-alive";
- }
-
- blockPool.concat(blocks);
- me.snakeHead.elm.className = me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/,'')
- me.snakeHead.elm.className += " snake-snakebody-alive";
- me.snakeHead.row = config.startRow || 1;
- me.snakeHead.col = config.startCol || 1;
- me.snakeHead.xPos = me.snakeHead.row * playingBoard.getBlockWidth();
- me.snakeHead.yPos = me.snakeHead.col * playingBoard.getBlockHeight();
- me.snakeHead.elm.style.left = me.snakeHead.xPos + "px";
- me.snakeHead.elm.style.top = me.snakeHead.yPos + "px";
- };
-
- // ---------------------------------------------------------------------
- // Initialize
- // ---------------------------------------------------------------------
-
- createBlocks(growthIncr*2);
- xPosShift[0] = 0;
- xPosShift[1] = playingBoard.getBlockWidth();
- xPosShift[2] = 0;
- xPosShift[3] = -1 * playingBoard.getBlockWidth();
-
- yPosShift[0] = -1 * playingBoard.getBlockHeight();
- yPosShift[1] = 0;
- yPosShift[2] = playingBoard.getBlockHeight();
- yPosShift[3] = 0;
- };
-})();
-
-/**
-* This class manages the food which the snake will eat.
-* @class Food
-* @constructor
-* @namespace SNAKE
-* @param {Object} config The configuration object for the class. Contains playingBoard (the SNAKE.Board that this food resides in).
-*/
-
-SNAKE.Food = SNAKE.Food || (function() {
-
- // -------------------------------------------------------------------------
- // Private static variables and methods
- // -------------------------------------------------------------------------
-
- var instanceNumber = 0;
-
- function getRandomPosition(x, y){
- return Math.floor(Math.random()*(y+1-x)) + x;
- }
-
- // -------------------------------------------------------------------------
- // Contructor + public and private definitions
- // -------------------------------------------------------------------------
-
- /*
- config options:
- playingBoard - the SnakeBoard that this object belongs too.
- */
- return function(config) {
-
- if (!config||!config.playingBoard) {return;}
-
- // ----- private variables -----
-
- var me = this;
- var playingBoard = config.playingBoard;
- var fRow, fColumn;
- var myId = instanceNumber++;
-
- var elmFood = document.createElement("div");
- elmFood.setAttribute("id", "snake-food-"+myId);
- elmFood.className = "snake-food-block";
- elmFood.style.width = playingBoard.getBlockWidth() + "px";
- elmFood.style.height = playingBoard.getBlockHeight() + "px";
- elmFood.style.left = "-1000px";
- elmFood.style.top = "-1000px";
- playingBoard.getBoardContainer().appendChild(elmFood);
-
- // ----- public methods -----
-
- /**
- * @method getFoodElement
- * @return {DOM Element} The div the represents the food.
- */
- me.getFoodElement = function() {
- return elmFood;
- };
-
- /**
- * Randomly places the food onto an available location on the playing board.
- * @method randomlyPlaceFood
- */
- me.randomlyPlaceFood = function() {
- // if there exist some food, clear its presence from the board
- if (playingBoard.grid[fRow] && playingBoard.grid[fRow][fColumn] === playingBoard.getGridFoodValue()){
- playingBoard.grid[fRow][fColumn] = 0;
- }
-
- var row = 0, col = 0, numTries = 0;
-
- var maxRows = playingBoard.grid.length-1;
- var maxCols = playingBoard.grid[0].length-1;
-
- while (playingBoard.grid[row][col] !== 0){
- row = getRandomPosition(1, maxRows);
- col = getRandomPosition(1, maxCols);
-
- // in some cases there may not be any room to put food anywhere
- // instead of freezing, exit out
- numTries++;
- if (numTries > 20000){
- row = -1;
- col = -1;
- break;
- }
- }
-
- playingBoard.grid[row][col] = playingBoard.getGridFoodValue();
- fRow = row;
- fColumn = col;
- elmFood.style.top = row * playingBoard.getBlockHeight() + "px";
- elmFood.style.left = col * playingBoard.getBlockWidth() + "px";
- };
- };
-})();
-
-/**
-* This class manages playing board for the game.
-* @class Board
-* @constructor
-* @namespace SNAKE
-* @param {Object} config The configuration object for the class. Set fullScreen equal to true if you want the game to take up the full screen, otherwise, set the top, left, width and height parameters.
-*/
-
-SNAKE.Board = SNAKE.Board || (function() {
-
- // -------------------------------------------------------------------------
- // Private static variables and methods
- // -------------------------------------------------------------------------
-
- var instanceNumber = 0;
-
- // this function is adapted from the example at http://greengeckodesign.com/blog/2007/07/get-highest-z-index-in-javascript.html
- function getNextHighestZIndex(myObj) {
- var highestIndex = 0,
- currentIndex = 0,
- ii;
- for (ii in myObj) {
- if (myObj[ii].elm.currentStyle){
- currentIndex = parseFloat(myObj[ii].elm.style["z-index"],10);
- }else if(window.getComputedStyle) {
- currentIndex = parseFloat(document.defaultView.getComputedStyle(myObj[ii].elm,null).getPropertyValue("z-index"),10);
- }
- if(!isNaN(currentIndex) && currentIndex > highestIndex){
- highestIndex = currentIndex;
- }
- }
- return(highestIndex+1);
- }
-
- /*
- This function returns the width of the available screen real estate that we have
- */
- function getClientWidth(){
- var myWidth = 0;
- if( typeof window.innerWidth === "number" ) {
- myWidth = window.innerWidth;//Non-IE
- } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
- myWidth = document.documentElement.clientWidth;//IE 6+ in 'standards compliant mode'
- } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
- myWidth = document.body.clientWidth;//IE 4 compatible
- }
- return myWidth;
- }
- /*
- This function returns the height of the available screen real estate that we have
- */
- function getClientHeight(){
- var myHeight = 0;
- if( typeof window.innerHeight === "number" ) {
- myHeight = window.innerHeight;//Non-IE
- } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
- myHeight = document.documentElement.clientHeight;//IE 6+ in 'standards compliant mode'
- } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
- myHeight = document.body.clientHeight;//IE 4 compatible
- }
- return myHeight;
- }
-
- // -------------------------------------------------------------------------
- // Contructor + public and private definitions
- // -------------------------------------------------------------------------
-
- return function(inputConfig) {
-
- // --- private variables ---
- var me = this,
- myId = instanceNumber++,
- config = inputConfig || {},
- MAX_BOARD_COLS = 250,
- MAX_BOARD_ROWS = 250,
- blockWidth = 20,
- blockHeight = 20,
- GRID_FOOD_VALUE = -1, // the value of a spot on the board that represents snake food, MUST BE NEGATIVE
- myFood,
- mySnake,
- boardState = 1, // 0: in active; 1: awaiting game start; 2: playing game
- myKeyListener,
- isPaused = false,//note: both the board and the snake can be paused
- // Board components
- elmContainer, elmPlayingField, elmAboutPanel, elmLengthPanel, elmWelcome, elmTryAgain, elmPauseScreen;
-
- // --- public variables ---
- me.grid = [];
-
- // ---------------------------------------------------------------------
- // private functions
- // ---------------------------------------------------------------------
-
- function createBoardElements() {
- elmPlayingField = document.createElement("div");
- elmPlayingField.setAttribute("id", "playingField");
- elmPlayingField.className = "snake-playing-field";
-
- SNAKE.addEventListener(elmPlayingField, "click", function() {
- elmContainer.focus();
- }, false);
-
- elmPauseScreen = document.createElement("div");
- elmPauseScreen.className = "snake-pause-screen";
- elmPauseScreen.innerHTML = "[Paused]
Press [space] to unpause.
";
-
- elmAboutPanel = document.createElement("div");
- elmAboutPanel.className = "snake-panel-component";
- elmAboutPanel.innerHTML = "more patorjk.com apps - source code";
-
- elmLengthPanel = document.createElement("div");
- elmLengthPanel.className = "snake-panel-component";
- elmLengthPanel.innerHTML = "Length: 1";
-
- elmWelcome = createWelcomeElement();
- elmTryAgain = createTryAgainElement();
-
- SNAKE.addEventListener( elmContainer, "keyup", function(evt) {
- if (!evt) var evt = window.event;
- evt.cancelBubble = true;
- if (evt.stopPropagation) {evt.stopPropagation();}
- if (evt.preventDefault) {evt.preventDefault();}
- return false;
- }, false);
-
- elmContainer.className = "snake-game-container";
-
- elmPauseScreen.style.zIndex = 10000;
- elmContainer.appendChild(elmPauseScreen);
- elmContainer.appendChild(elmPlayingField);
- elmContainer.appendChild(elmAboutPanel);
- elmContainer.appendChild(elmLengthPanel);
- elmContainer.appendChild(elmWelcome);
- elmContainer.appendChild(elmTryAgain);
-
- mySnake = new SNAKE.Snake({playingBoard:me,startRow:2,startCol:2});
- myFood = new SNAKE.Food({playingBoard: me});
-
- elmWelcome.style.zIndex = 1000;
- }
- function maxBoardWidth() {
- return MAX_BOARD_COLS * me.getBlockWidth();
- }
- function maxBoardHeight() {
- return MAX_BOARD_ROWS * me.getBlockHeight();
- }
-
- function createWelcomeElement() {
- var tmpElm = document.createElement("div");
- tmpElm.id = "sbWelcome" + myId;
- tmpElm.className = "snake-welcome-dialog";
-
- var welcomeTxt = document.createElement("div");
- var fullScreenText = "";
- if (config.fullScreen) {
- fullScreenText = "On Windows, press F11 to play in Full Screen mode.";
- }
- welcomeTxt.innerHTML = "JavaScript SnakeUse the arrow keys on your keyboard to play the game. " + fullScreenText + "";
- var welcomeStart = document.createElement("button");
- welcomeStart.appendChild( document.createTextNode("Play Game"));
-
- var loadGame = function() {
- SNAKE.removeEventListener(window, "keyup", kbShortcut, false);
- tmpElm.style.display = "none";
- me.setBoardState(1);
- me.getBoardContainer().focus();
- };
-
- var kbShortcut = function(evt) {
- if (!evt) var evt = window.event;
- var keyNum = (evt.which) ? evt.which : evt.keyCode;
- if (keyNum === 32 || keyNum === 13) {
- loadGame();
- }
- };
- SNAKE.addEventListener(window, "keyup", kbShortcut, false);
- SNAKE.addEventListener(welcomeStart, "click", loadGame, false);
-
- tmpElm.appendChild(welcomeTxt);
- tmpElm.appendChild(welcomeStart);
- return tmpElm;
- }
-
- function createTryAgainElement() {
- var tmpElm = document.createElement("div");
- tmpElm.id = "sbTryAgain" + myId;
- tmpElm.className = "snake-try-again-dialog";
-
- var tryAgainTxt = document.createElement("div");
- tryAgainTxt.innerHTML = "JavaScript SnakeYou died :(.";
- var tryAgainStart = document.createElement("button");
- tryAgainStart.appendChild( document.createTextNode("Play Again?"));
-
- var reloadGame = function() {
- tmpElm.style.display = "none";
- me.resetBoard();
- me.setBoardState(1);
- me.getBoardContainer().focus();
- };
-
- var kbTryAgainShortcut = function(evt) {
- if (boardState !== 0 || tmpElm.style.display !== "block") {return;}
- if (!evt) var evt = window.event;
- var keyNum = (evt.which) ? evt.which : evt.keyCode;
- if (keyNum === 32 || keyNum === 13) {
- reloadGame();
- }
- };
- SNAKE.addEventListener(window, "keyup", kbTryAgainShortcut, true);
-
- SNAKE.addEventListener(tryAgainStart, "click", reloadGame, false);
- tmpElm.appendChild(tryAgainTxt);
- tmpElm.appendChild(tryAgainStart);
- return tmpElm;
- }
-
- // ---------------------------------------------------------------------
- // public functions
- // ---------------------------------------------------------------------
-
- me.setPaused = function(val) {
- isPaused = val;
- mySnake.setPaused(val);
- if (isPaused) {
- elmPauseScreen.style.display = "block";
- } else {
- elmPauseScreen.style.display = "none";
- }
- };
- me.getPaused = function() {
- return isPaused;
- };
-
- /**
- * Resets the playing board for a new game.
- * @method resetBoard
- */
- me.resetBoard = function() {
- SNAKE.removeEventListener(elmContainer, "keydown", myKeyListener, false);
- mySnake.reset();
- elmLengthPanel.innerHTML = "Length: 1";
- me.setupPlayingField();
- };
- /**
- * Gets the current state of the playing board. There are 3 states: 0 - Welcome or Try Again dialog is present. 1 - User has pressed "Start Game" on the Welcome or Try Again dialog but has not pressed an arrow key to move the snake. 2 - The game is in progress and the snake is moving.
- * @method getBoardState
- * @return {Number} The state of the board.
- */
- me.getBoardState = function() {
- return boardState;
- };
- /**
- * Sets the current state of the playing board. There are 3 states: 0 - Welcome or Try Again dialog is present. 1 - User has pressed "Start Game" on the Welcome or Try Again dialog but has not pressed an arrow key to move the snake. 2 - The game is in progress and the snake is moving.
- * @method setBoardState
- * @param {Number} state The state of the board.
- */
- me.setBoardState = function(state) {
- boardState = state;
- };
- /**
- * @method getGridFoodValue
- * @return {Number} A number that represents food on a number representation of the playing board.
- */
- me.getGridFoodValue = function() {
- return GRID_FOOD_VALUE;
- };
- /**
- * @method getPlayingFieldElement
- * @return {DOM Element} The div representing the playing field (this is where the snake can move).
- */
- me.getPlayingFieldElement = function() {
- return elmPlayingField;
- };
- /**
- * @method setBoardContainer
- * @param {DOM Element or String} myContainer Sets the container element for the game.
- */
- me.setBoardContainer = function(myContainer) {
- if (typeof myContainer === "string") {
- myContainer = document.getElementById(myContainer);
- }
- if (myContainer === elmContainer) {return;}
- elmContainer = myContainer;
- elmPlayingField = null;
-
- me.setupPlayingField();
- };
- /**
- * @method getBoardContainer
- * @return {DOM Element}
- */
- me.getBoardContainer = function() {
- return elmContainer;
- };
- /**
- * @method getBlockWidth
- * @return {Number}
- */
- me.getBlockWidth = function() {
- return blockWidth;
- };
- /**
- * @method getBlockHeight
- * @return {Number}
- */
- me.getBlockHeight = function() {
- return blockHeight;
- };
- /**
- * Sets up the playing field.
- * @method setupPlayingField
- */
- me.setupPlayingField = function () {
-
- if (!elmPlayingField) {createBoardElements();} // create playing field
-
- // calculate width of our game container
- var cWidth, cHeight;
- if (config.fullScreen === true) {
- cTop = 0;
- cLeft = 0;
- cWidth = getClientWidth()-5;
- cHeight = getClientHeight()-5;
- document.body.style.backgroundColor = "#FC5454";
- } else {
- cTop = config.top;
- cLeft = config.left;
- cWidth = config.width;
- cHeight = config.height;
- }
-
- // define the dimensions of the board and playing field
- var wEdgeSpace = me.getBlockWidth()*2 + (cWidth % me.getBlockWidth());
- var fWidth = Math.min(maxBoardWidth()-wEdgeSpace,cWidth-wEdgeSpace);
- var hEdgeSpace = me.getBlockHeight()*3 + (cHeight % me.getBlockHeight());
- var fHeight = Math.min(maxBoardHeight()-hEdgeSpace,cHeight-hEdgeSpace);
-
- elmContainer.style.left = cLeft + "px";
- elmContainer.style.top = cTop + "px";
- elmContainer.style.width = cWidth + "px";
- elmContainer.style.height = cHeight + "px";
- elmPlayingField.style.left = me.getBlockWidth() + "px";
- elmPlayingField.style.top = me.getBlockHeight() + "px";
- elmPlayingField.style.width = fWidth + "px";
- elmPlayingField.style.height = fHeight + "px";
-
- // the math for this will need to change depending on font size, padding, etc
- // assuming height of 14 (font size) + 8 (padding)
- var bottomPanelHeight = hEdgeSpace - me.getBlockHeight();
- var pLabelTop = me.getBlockHeight() + fHeight + Math.round((bottomPanelHeight - 30)/2) + "px";
-
- elmAboutPanel.style.top = pLabelTop;
- elmAboutPanel.style.width = "450px";
- elmAboutPanel.style.left = Math.round(cWidth/2) - Math.round(450/2) + "px";
-
- elmLengthPanel.style.top = pLabelTop;
- elmLengthPanel.style.left = cWidth - 120 + "px";
-
- // if width is too narrow, hide the about panel
- if (cWidth < 700) {
- elmAboutPanel.style.display = "none";
- } else {
- elmAboutPanel.style.display = "block";
- }
-
- me.grid = [];
- var numBoardCols = fWidth / me.getBlockWidth() + 2;
- var numBoardRows = fHeight / me.getBlockHeight() + 2;
-
- for (var row = 0; row < numBoardRows; row++) {
- me.grid[row] = [];
- for (var col = 0; col < numBoardCols; col++) {
- if (col === 0 || row === 0 || col === (numBoardCols-1) || row === (numBoardRows-1)) {
- me.grid[row][col] = 1; // an edge
- } else {
- me.grid[row][col] = 0; // empty space
- }
- }
- }
-
- myFood.randomlyPlaceFood();
-
- // setup event listeners
-
- myKeyListener = function(evt) {
- if (!evt) var evt = window.event;
- var keyNum = (evt.which) ? evt.which : evt.keyCode;
-
- if (me.getBoardState() === 1) {
- if ( !(keyNum >= 37 && keyNum <= 40) && !(keyNum === 87 || keyNum === 65 || keyNum === 83 || keyNum === 68)) {return;} // if not an arrow key, leave
-
- // This removes the listener added at the #listenerX line
- SNAKE.removeEventListener(elmContainer, "keydown", myKeyListener, false);
-
- myKeyListener = function(evt) {
- if (!evt) var evt = window.event;
- var keyNum = (evt.which) ? evt.which : evt.keyCode;
-
- //console.log(keyNum);
- if (keyNum === 32) {
- me.setPaused(!me.getPaused());
- }
-
- mySnake.handleArrowKeys(keyNum);
-
- evt.cancelBubble = true;
- if (evt.stopPropagation) {evt.stopPropagation();}
- if (evt.preventDefault) {evt.preventDefault();}
- return false;
- };
- SNAKE.addEventListener( elmContainer, "keydown", myKeyListener, false);
-
- mySnake.rebirth();
- mySnake.handleArrowKeys(keyNum);
- me.setBoardState(2); // start the game!
- mySnake.go();
- }
-
- evt.cancelBubble = true;
- if (evt.stopPropagation) {evt.stopPropagation();}
- if (evt.preventDefault) {evt.preventDefault();}
- return false;
- };
-
- // Search for #listenerX to see where this is removed
- SNAKE.addEventListener( elmContainer, "keydown", myKeyListener, false);
- };
-
- /**
- * This method is called when the snake has eaten some food.
- * @method foodEaten
- */
- me.foodEaten = function() {
- elmLengthPanel.innerHTML = "Length: " + mySnake.snakeLength;
- myFood.randomlyPlaceFood();
- };
-
- /**
- * This method is called when the snake dies.
- * @method handleDeath
- */
- me.handleDeath = function() {
- var index = Math.max(getNextHighestZIndex( mySnake.snakeBody), getNextHighestZIndex( {tmp:{elm:myFood.getFoodElement()}} ));
- elmContainer.removeChild(elmTryAgain);
- elmContainer.appendChild(elmTryAgain);
- elmTryAgain.style.zIndex = index;
- elmTryAgain.style.display = "block";
- me.setBoardState(0);
- };
-
- // ---------------------------------------------------------------------
- // Initialize
- // ---------------------------------------------------------------------
-
- config.fullScreen = (typeof config.fullScreen === "undefined") ? false : config.fullScreen;
- config.top = (typeof config.top === "undefined") ? 0 : config.top;
- config.left = (typeof config.left === "undefined") ? 0 : config.left;
- config.width = (typeof config.width === "undefined") ? 400 : config.width;
- config.height = (typeof config.height === "undefined") ? 400 : config.height;
-
- if (config.fullScreen) {
- SNAKE.addEventListener(window,"resize", function() {
- me.setupPlayingField();
- }, false);
- }
-
- me.setBoardState(0);
-
- if (config.boardContainer) {
- me.setBoardContainer(config.boardContainer);
- }
-
- }; // end return function
-})();
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..d7f43490
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,3389 @@
+{
+ "name": "javascript-snake",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "javascript-snake",
+ "version": "1.0.0",
+ "license": "MIT",
+ "devDependencies": {
+ "parcel": "^2.13.3",
+ "parcel-reporter-static-files-copy": "^1.5.3"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.26.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+ "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@lezer/common": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
+ "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@lezer/lr": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
+ "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.0.0"
+ }
+ },
+ "node_modules/@lmdb/lmdb-darwin-arm64": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.8.5.tgz",
+ "integrity": "sha512-KPDeVScZgA1oq0CiPBcOa3kHIqU+pTOwRFDIhxvmf8CTNvqdZQYp5cCKW0bUk69VygB2PuTiINFWbY78aR2pQw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@lmdb/lmdb-darwin-x64": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.8.5.tgz",
+ "integrity": "sha512-w/sLhN4T7MW1nB3R/U8WK5BgQLz904wh+/SmA2jD8NnF7BLLoUgflCNxOeSPOWp8geP6nP/+VjWzZVip7rZ1ug==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@lmdb/lmdb-linux-arm": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.8.5.tgz",
+ "integrity": "sha512-c0TGMbm2M55pwTDIfkDLB6BpIsgxV4PjYck2HiOX+cy/JWiBXz32lYbarPqejKs9Flm7YVAKSILUducU9g2RVg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@lmdb/lmdb-linux-arm64": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.8.5.tgz",
+ "integrity": "sha512-vtbZRHH5UDlL01TT5jB576Zox3+hdyogvpcbvVJlmU5PdL3c5V7cj1EODdh1CHPksRl+cws/58ugEHi8bcj4Ww==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@lmdb/lmdb-linux-x64": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.8.5.tgz",
+ "integrity": "sha512-Xkc8IUx9aEhP0zvgeKy7IQ3ReX2N8N1L0WPcQwnZweWmOuKfwpS3GRIYqLtK5za/w3E60zhFfNdS+3pBZPytqQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@lmdb/lmdb-win32-x64": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.8.5.tgz",
+ "integrity": "sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@mischnic/json-sourcemap": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz",
+ "integrity": "sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@lezer/common": "^1.0.0",
+ "@lezer/lr": "^1.0.0",
+ "json5": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
+ "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
+ "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
+ "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
+ "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
+ "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
+ "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@parcel/bundler-default": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.13.3.tgz",
+ "integrity": "sha512-mOuWeth0bZzRv1b9Lrvydis/hAzJyePy0gwa0tix3/zyYBvw0JY+xkXVR4qKyD/blc1Ra2qOlfI2uD3ucnsdXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/graph": "3.3.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/cache": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.13.3.tgz",
+ "integrity": "sha512-Vz5+K5uCt9mcuQAMDo0JdbPYDmVdB8Nvu/A2vTEK2rqZPxvoOTczKeMBA4JqzKqGURHPRLaJCvuR8nDG+jhK9A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/fs": "2.13.3",
+ "@parcel/logger": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "lmdb": "2.8.5"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "peerDependencies": {
+ "@parcel/core": "^2.13.3"
+ }
+ },
+ "node_modules/@parcel/codeframe": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.13.3.tgz",
+ "integrity": "sha512-L/PQf+PT0xM8k9nc0B+PxxOYO2phQYnbuifu9o4pFRiqVmCtHztP+XMIvRJ2gOEXy3pgAImSPFVJ3xGxMFky4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/compressor-raw": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.13.3.tgz",
+ "integrity": "sha512-C6vjDlgTLjYc358i7LA/dqcL0XDQZ1IHXFw6hBaHHOfxPKW2T4bzUI6RURyToEK9Q1X7+ggDKqgdLxwp4veCFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/config-default": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.13.3.tgz",
+ "integrity": "sha512-WUsx83ic8DgLwwnL1Bua4lRgQqYjxiTT+DBxESGk1paNm1juWzyfPXEQDLXwiCTcWMQGiXQFQ8OuSISauVQ8dQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/bundler-default": "2.13.3",
+ "@parcel/compressor-raw": "2.13.3",
+ "@parcel/namer-default": "2.13.3",
+ "@parcel/optimizer-css": "2.13.3",
+ "@parcel/optimizer-htmlnano": "2.13.3",
+ "@parcel/optimizer-image": "2.13.3",
+ "@parcel/optimizer-svgo": "2.13.3",
+ "@parcel/optimizer-swc": "2.13.3",
+ "@parcel/packager-css": "2.13.3",
+ "@parcel/packager-html": "2.13.3",
+ "@parcel/packager-js": "2.13.3",
+ "@parcel/packager-raw": "2.13.3",
+ "@parcel/packager-svg": "2.13.3",
+ "@parcel/packager-wasm": "2.13.3",
+ "@parcel/reporter-dev-server": "2.13.3",
+ "@parcel/resolver-default": "2.13.3",
+ "@parcel/runtime-browser-hmr": "2.13.3",
+ "@parcel/runtime-js": "2.13.3",
+ "@parcel/runtime-react-refresh": "2.13.3",
+ "@parcel/runtime-service-worker": "2.13.3",
+ "@parcel/transformer-babel": "2.13.3",
+ "@parcel/transformer-css": "2.13.3",
+ "@parcel/transformer-html": "2.13.3",
+ "@parcel/transformer-image": "2.13.3",
+ "@parcel/transformer-js": "2.13.3",
+ "@parcel/transformer-json": "2.13.3",
+ "@parcel/transformer-postcss": "2.13.3",
+ "@parcel/transformer-posthtml": "2.13.3",
+ "@parcel/transformer-raw": "2.13.3",
+ "@parcel/transformer-react-refresh-wrap": "2.13.3",
+ "@parcel/transformer-svg": "2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "peerDependencies": {
+ "@parcel/core": "^2.13.3"
+ }
+ },
+ "node_modules/@parcel/core": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.13.3.tgz",
+ "integrity": "sha512-SRZFtqGiaKHlZ2YAvf+NHvBFWS3GnkBvJMfOJM7kxJRK3M1bhbwJa/GgSdzqro5UVf9Bfj6E+pkdrRQIOZ7jMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@mischnic/json-sourcemap": "^0.1.0",
+ "@parcel/cache": "2.13.3",
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/events": "2.13.3",
+ "@parcel/feature-flags": "2.13.3",
+ "@parcel/fs": "2.13.3",
+ "@parcel/graph": "3.3.3",
+ "@parcel/logger": "2.13.3",
+ "@parcel/package-manager": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/profiler": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "@parcel/types": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "@parcel/workers": "2.13.3",
+ "base-x": "^3.0.8",
+ "browserslist": "^4.6.6",
+ "clone": "^2.1.1",
+ "dotenv": "^16.4.5",
+ "dotenv-expand": "^11.0.6",
+ "json5": "^2.2.0",
+ "msgpackr": "^1.9.9",
+ "nullthrows": "^1.1.1",
+ "semver": "^7.5.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/diagnostic": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.13.3.tgz",
+ "integrity": "sha512-C70KXLBaXLJvr7XCEVu8m6TqNdw1gQLxqg5BQ8roR62R4vWWDnOq8PEksxDi4Y8Z/FF4i3Sapv6tRx9iBNxDEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@mischnic/json-sourcemap": "^0.1.0",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/events": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.13.3.tgz",
+ "integrity": "sha512-ZkSHTTbD/E+53AjUzhAWTnMLnxLEU5yRw0H614CaruGh+GjgOIKyukGeToF5Gf/lvZ159VrJCGE0Z5EpgHVkuQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/feature-flags": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/feature-flags/-/feature-flags-2.13.3.tgz",
+ "integrity": "sha512-UZm14QpamDFoUut9YtCZSpG1HxPs07lUwUCpsAYL0PpxASD3oWJQxIJGfDZPa2272DarXDG9adTKrNXvkHZblw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/fs": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.13.3.tgz",
+ "integrity": "sha512-+MPWAt0zr+TCDSlj1LvkORTjfB/BSffsE99A9AvScKytDSYYpY2s0t4vtV9unSh0FHMS2aBCZNJ4t7KL+DcPIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/feature-flags": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/types-internal": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "@parcel/watcher": "^2.0.7",
+ "@parcel/workers": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "peerDependencies": {
+ "@parcel/core": "^2.13.3"
+ }
+ },
+ "node_modules/@parcel/graph": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-3.3.3.tgz",
+ "integrity": "sha512-pxs4GauEdvCN8nRd6wG3st6LvpHske3GfqGwUSR0P0X0pBPI1/NicvXz6xzp3rgb9gPWfbKXeI/2IOTfIxxVfg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/feature-flags": "2.13.3",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/logger": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.13.3.tgz",
+ "integrity": "sha512-8YF/ZhsQgd7ohQ2vEqcMD1Ag9JlJULROWRPGgGYLGD+twuxAiSdiFBpN3f+j4gQN4PYaLaIS/SwUFx11J243fQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/events": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/markdown-ansi": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.13.3.tgz",
+ "integrity": "sha512-B4rUdlNUulJs2xOQuDbN7Hq5a9roq8IZUcJ1vQ8PAv+zMGb7KCfqIIr/BSCDYGhayfAGBVWW8x55Kvrl1zrDYw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/namer-default": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.13.3.tgz",
+ "integrity": "sha512-A2a5A5fuyNcjSGOS0hPcdQmOE2kszZnLIXof7UMGNkNkeC62KAG8WcFZH5RNOY3LT5H773hq51zmc2Y2gE5Rnw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/node-resolver-core": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.4.3.tgz",
+ "integrity": "sha512-IEnMks49egEic1ITBp59VQyHzkSQUXqpU9hOHwqN3KoSTdZ6rEgrXcS3pa6tdXay4NYGlcZ88kFCE8i/xYoVCg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@mischnic/json-sourcemap": "^0.1.0",
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/fs": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "nullthrows": "^1.1.1",
+ "semver": "^7.5.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/optimizer-css": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.13.3.tgz",
+ "integrity": "sha512-A8o9IVCv919vhv69SkLmyW2WjJR5WZgcMqV6L1uiGF8i8z18myrMhrp2JuSHx29PRT9uNyzNC4Xrd4StYjIhJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "@parcel/utils": "2.13.3",
+ "browserslist": "^4.6.6",
+ "lightningcss": "^1.22.1",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/optimizer-htmlnano": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.13.3.tgz",
+ "integrity": "sha512-K4Uvg0Sy2pECP7pdvvbud++F0pfcbNkq+IxTrgqBX5HJnLEmRZwgdvZEKF43oMEolclMnURMQRGjRplRaPdbXg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "htmlnano": "^2.0.0",
+ "nullthrows": "^1.1.1",
+ "posthtml": "^0.16.5"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/optimizer-image": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.13.3.tgz",
+ "integrity": "sha512-wlDUICA29J4UnqkKrWiyt68g1e85qfYhp4zJFcFJL0LX1qqh1QwsLUz3YJ+KlruoqPxJSFEC8ncBEKiVCsqhEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "@parcel/workers": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "peerDependencies": {
+ "@parcel/core": "^2.13.3"
+ }
+ },
+ "node_modules/@parcel/optimizer-svgo": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.13.3.tgz",
+ "integrity": "sha512-piIKxQKzhZK54dJR6yqIcq+urZmpsfgUpLCZT3cnWlX4ux5+S2iN66qqZBs0zVn+a58LcWcoP4Z9ieiJmpiu2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/optimizer-swc": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.13.3.tgz",
+ "integrity": "sha512-zNSq6oWqLlW8ksPIDjM0VgrK6ZAJbPQCDvs1V+p0oX3CzEe85lT5VkRpnfrN1+/vvEJNGL8e60efHKpI+rXGTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "@parcel/utils": "2.13.3",
+ "@swc/core": "^1.7.26",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/package-manager": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.13.3.tgz",
+ "integrity": "sha512-FLNI5OrZxymGf/Yln0E/kjnGn5sdkQAxW7pQVdtuM+5VeN75yibJRjsSGv88PvJ+KvpD2ANgiIJo1RufmoPcww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/fs": "2.13.3",
+ "@parcel/logger": "2.13.3",
+ "@parcel/node-resolver-core": "3.4.3",
+ "@parcel/types": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "@parcel/workers": "2.13.3",
+ "@swc/core": "^1.7.26",
+ "semver": "^7.5.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "peerDependencies": {
+ "@parcel/core": "^2.13.3"
+ }
+ },
+ "node_modules/@parcel/packager-css": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.13.3.tgz",
+ "integrity": "sha512-ghDqRMtrUwaDERzFm9le0uz2PTeqqsjsW0ihQSZPSAptElRl9o5BR+XtMPv3r7Ui0evo+w35gD55oQCJ28vCig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "@parcel/utils": "2.13.3",
+ "lightningcss": "^1.22.1",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/packager-html": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.13.3.tgz",
+ "integrity": "sha512-jDLnKSA/EzVEZ3/aegXO3QJ/Ij732AgBBkIQfeC8tUoxwVz5b3HiPBAjVjcUSfZs7mdBSHO+ELWC3UD+HbsIrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/types": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "nullthrows": "^1.1.1",
+ "posthtml": "^0.16.5"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/packager-js": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.13.3.tgz",
+ "integrity": "sha512-0pMHHf2zOn7EOJe88QJw5h/wcV1bFfj6cXVcE55Wa8GX3V+SdCgolnlvNuBcRQ1Tlx0Xkpo+9hMFVIQbNQY6zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "@parcel/types": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "globals": "^13.2.0",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/packager-raw": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.13.3.tgz",
+ "integrity": "sha512-AWu4UB+akBdskzvT3KGVHIdacU9f7cI678DQQ1jKQuc9yZz5D0VFt3ocFBOmvDfEQDF0uH3jjtJR7fnuvX7Biw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/packager-svg": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.13.3.tgz",
+ "integrity": "sha512-tKGRiFq/4jh5u2xpTstNQ7gu+RuZWzlWqpw5NaFmcKe6VQe5CMcS499xTFoREAGnRvevSeIgC38X1a+VOo+/AA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/types": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "posthtml": "^0.16.4"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/packager-wasm": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/packager-wasm/-/packager-wasm-2.13.3.tgz",
+ "integrity": "sha512-SZB56/b230vFrSehVXaUAWjJmWYc89gzb8OTLkBm7uvtFtov2J1R8Ig9TTJwinyXE3h84MCFP/YpQElSfoLkJw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3"
+ },
+ "engines": {
+ "node": ">=16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/plugin": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.13.3.tgz",
+ "integrity": "sha512-cterKHHcwg6q11Gpif/aqvHo056TR+yDVJ3fSdiG2xr5KD1VZ2B3hmofWERNNwjMcnR1h9Xq40B7jCKUhOyNFA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/types": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/profiler": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.13.3.tgz",
+ "integrity": "sha512-ok6BwWSLvyHe5TuSXjSacYnDStFgP5Y30tA9mbtWSm0INDsYf+m5DqzpYPx8U54OaywWMK8w3MXUClosJX3aPA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/events": "2.13.3",
+ "@parcel/types-internal": "2.13.3",
+ "chrome-trace-event": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/reporter-cli": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.13.3.tgz",
+ "integrity": "sha512-EA5tKt/6bXYNMEavSs35qHlFdx6cZmRazlZxPBgxPePQYoouNAPMNLUOEQozaPhz9f5fvNDN7EHOFaAWcdO2LA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/types": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "chalk": "^4.1.2",
+ "term-size": "^2.2.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/reporter-dev-server": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.13.3.tgz",
+ "integrity": "sha512-ZNeFp6AOIQFv7mZIv2P5O188dnZHNg0ymeDVcakfZomwhpSva2dFNS3AnvWo4eyWBlUxkmQO8BtaxeWTs7jAuA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/reporter-tracer": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.13.3.tgz",
+ "integrity": "sha512-aBsVPI8jLZTDkFYrI69GxnsdvZKEYerkPsu935LcX9rfUYssOnmmUP+3oI+8fbg+qNjJuk9BgoQ4hCp9FOphMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "chrome-trace-event": "^1.0.3",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/resolver-default": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.13.3.tgz",
+ "integrity": "sha512-urBZuRALWT9pFMeWQ8JirchLmsQEyI9lrJptiwLbJWrwvmlwSUGkcstmPwoNRf/aAQjICB7ser/247Vny0pFxA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/node-resolver-core": "3.4.3",
+ "@parcel/plugin": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/runtime-browser-hmr": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.13.3.tgz",
+ "integrity": "sha512-EAcPojQFUNUGUrDk66cu3ySPO0NXRVS5CKPd4QrxPCVVbGzde4koKu8krC/TaGsoyUqhie8HMnS70qBP0GFfcQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/runtime-js": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.13.3.tgz",
+ "integrity": "sha512-62OucNAnxb2Q0uyTFWW/0Hvv2DJ4b5H6neh/YFu2/wmxaZ37xTpEuEcG2do7KW54xE5DeLP+RliHLwi4NvR3ww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/runtime-react-refresh": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.13.3.tgz",
+ "integrity": "sha512-PYZ1klpJVwqE3WuifILjtF1dugtesHEuJcXYZI85T6UoRSD5ctS1nAIpZzT14Ga1lRt/jd+eAmhWL1l3m/Vk1Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "react-error-overlay": "6.0.9",
+ "react-refresh": ">=0.9 <=0.14"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/runtime-service-worker": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.13.3.tgz",
+ "integrity": "sha512-BjMhPuT7Us1+YIo31exPRwomPiL+jrZZS5UUAwlEW2XGHDceEotzRM94LwxeFliCScT4IOokGoxixm19qRuzWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/rust": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/rust/-/rust-2.13.3.tgz",
+ "integrity": "sha512-dLq85xDAtzr3P5200cvxk+8WXSWauYbxuev9LCPdwfhlaWo/JEj6cu9seVdWlkagjGwkoV1kXC+GGntgUXOLAQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/source-map": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@parcel/source-map/-/source-map-2.1.1.tgz",
+ "integrity": "sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^1.0.3"
+ },
+ "engines": {
+ "node": "^12.18.3 || >=14"
+ }
+ },
+ "node_modules/@parcel/transformer-babel": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.13.3.tgz",
+ "integrity": "sha512-ikzK9f5WTFrdQsPitQgjCPH6HmVU8AQPRemIJ2BndYhtodn5PQut5cnSvTrqax8RjYvheEKCQk/Zb/uR7qgS3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "@parcel/utils": "2.13.3",
+ "browserslist": "^4.6.6",
+ "json5": "^2.2.0",
+ "nullthrows": "^1.1.1",
+ "semver": "^7.5.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/transformer-css": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.13.3.tgz",
+ "integrity": "sha512-zbrNURGph6JeVADbGydyZ7lcu/izj41kDxQ9xw4RPRW/3rofQiTU0OTREi+uBWiMENQySXVivEdzHA9cA+aLAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "@parcel/utils": "2.13.3",
+ "browserslist": "^4.6.6",
+ "lightningcss": "^1.22.1",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/transformer-html": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.13.3.tgz",
+ "integrity": "sha512-Yf74FkL9RCCB4+hxQRVMNQThH9+fZ5w0NLiQPpWUOcgDEEyxTi4FWPQgEBsKl/XK2ehdydbQB9fBgPQLuQxwPg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "nullthrows": "^1.1.1",
+ "posthtml": "^0.16.5",
+ "posthtml-parser": "^0.12.1",
+ "posthtml-render": "^3.0.0",
+ "semver": "^7.5.2",
+ "srcset": "4"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/transformer-html/node_modules/srcset": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/srcset/-/srcset-4.0.0.tgz",
+ "integrity": "sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@parcel/transformer-image": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.13.3.tgz",
+ "integrity": "sha512-wL1CXyeFAqbp2wcEq/JD3a/tbAyVIDMTC6laQxlIwnVV7dsENhK1qRuJZuoBdixESeUpFQSmmQvDIhcfT/cUUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "@parcel/workers": "2.13.3",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "peerDependencies": {
+ "@parcel/core": "^2.13.3"
+ }
+ },
+ "node_modules/@parcel/transformer-js": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.13.3.tgz",
+ "integrity": "sha512-KqfNGn1IHzDoN2aPqt4nDksgb50Xzcny777C7A7hjlQ3cmkjyJrixYjzzsPaPSGJ+kJpknh3KE8unkQ9mhFvRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "@parcel/utils": "2.13.3",
+ "@parcel/workers": "2.13.3",
+ "@swc/helpers": "^0.5.0",
+ "browserslist": "^4.6.6",
+ "nullthrows": "^1.1.1",
+ "regenerator-runtime": "^0.14.1",
+ "semver": "^7.5.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "peerDependencies": {
+ "@parcel/core": "^2.13.3"
+ }
+ },
+ "node_modules/@parcel/transformer-json": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.13.3.tgz",
+ "integrity": "sha512-rrq0ab6J0w9ePtsxi0kAvpCmrUYXXAx1Z5PATZakv89rSYbHBKEdXxyCoKFui/UPVCUEGVs5r0iOFepdHpIyeA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "json5": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/transformer-postcss": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.13.3.tgz",
+ "integrity": "sha512-AIiWpU0QSFBrPcYIqAnhqB8RGE6yHFznnxztfg1t2zMSOnK3xoU6xqYKv8H/MduShGGrC3qVOeDfM8MUwzL3cw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "clone": "^2.1.1",
+ "nullthrows": "^1.1.1",
+ "postcss-value-parser": "^4.2.0",
+ "semver": "^7.5.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/transformer-posthtml": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.13.3.tgz",
+ "integrity": "sha512-5GSLyccpHASwFAu3uJ83gDIBSvfsGdVmhJvy0Vxe+K1Fklk2ibhvvtUHMhB7mg6SPHC+R9jsNc3ZqY04ZLeGjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "nullthrows": "^1.1.1",
+ "posthtml": "^0.16.5",
+ "posthtml-parser": "^0.12.1",
+ "posthtml-render": "^3.0.0",
+ "semver": "^7.5.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/transformer-raw": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.13.3.tgz",
+ "integrity": "sha512-BFsAbdQF0l8/Pdb7dSLJeYcd8jgwvAUbHgMink2MNXJuRUvDl19Gns8jVokU+uraFHulJMBj40+K/RTd33in4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/transformer-react-refresh-wrap": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.13.3.tgz",
+ "integrity": "sha512-mOof4cRyxsZRdg8kkWaFtaX98mHpxUhcGPU+nF9RQVa9q737ItxrorsPNR9hpZAyE2TtFNflNW7RoYsgvlLw8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "react-refresh": ">=0.9 <=0.14"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/transformer-svg": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.13.3.tgz",
+ "integrity": "sha512-9jm7ZF4KHIrGLWlw/SFUz5KKJ20nxHvjFAmzde34R9Wu+F1BOjLZxae7w4ZRwvIc+UVOUcBBQFmhSVwVDZg6Dw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/plugin": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "nullthrows": "^1.1.1",
+ "posthtml": "^0.16.5",
+ "posthtml-parser": "^0.12.1",
+ "posthtml-render": "^3.0.0",
+ "semver": "^7.5.2"
+ },
+ "engines": {
+ "node": ">= 16.0.0",
+ "parcel": "^2.13.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/types": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.13.3.tgz",
+ "integrity": "sha512-+RpFHxx8fy8/dpuehHUw/ja9PRExC3wJoIlIIF42E7SLu2SvlTHtKm6EfICZzxCXNEBzjoDbamCRcN0nmTPlhw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/types-internal": "2.13.3",
+ "@parcel/workers": "2.13.3"
+ }
+ },
+ "node_modules/@parcel/types-internal": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/types-internal/-/types-internal-2.13.3.tgz",
+ "integrity": "sha512-Lhx0n+9RCp+Ipktf/I+CLm3zE9Iq9NtDd8b2Vr5lVWyoT8AbzBKIHIpTbhLS4kjZ80L3I6o93OYjqAaIjsqoZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/feature-flags": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "utility-types": "^3.10.0"
+ }
+ },
+ "node_modules/@parcel/utils": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.13.3.tgz",
+ "integrity": "sha512-yxY9xw2wOUlJaScOXYZmMGoZ4Ck4Kqj+p6Koe5kLkkWM1j98Q0Dj2tf/mNvZi4yrdnlm+dclCwNRnuE8Q9D+pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/codeframe": "2.13.3",
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/logger": "2.13.3",
+ "@parcel/markdown-ansi": "2.13.3",
+ "@parcel/rust": "2.13.3",
+ "@parcel/source-map": "^2.1.1",
+ "chalk": "^4.1.2",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
+ "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "is-glob": "^4.0.3",
+ "micromatch": "^4.0.5",
+ "node-addon-api": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.1",
+ "@parcel/watcher-darwin-arm64": "2.5.1",
+ "@parcel/watcher-darwin-x64": "2.5.1",
+ "@parcel/watcher-freebsd-x64": "2.5.1",
+ "@parcel/watcher-linux-arm-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm-musl": "2.5.1",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm64-musl": "2.5.1",
+ "@parcel/watcher-linux-x64-glibc": "2.5.1",
+ "@parcel/watcher-linux-x64-musl": "2.5.1",
+ "@parcel/watcher-win32-arm64": "2.5.1",
+ "@parcel/watcher-win32-ia32": "2.5.1",
+ "@parcel/watcher-win32-x64": "2.5.1"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
+ "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
+ "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
+ "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
+ "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
+ "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
+ "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
+ "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
+ "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
+ "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
+ "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
+ "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
+ "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
+ "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/workers": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.13.3.tgz",
+ "integrity": "sha512-oAHmdniWTRwwwsKbcF4t3VjOtKN+/W17Wj5laiYB+HLkfsjGTfIQPj3sdXmrlBAGpI4omIcvR70PHHXnfdTfwA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/logger": "2.13.3",
+ "@parcel/profiler": "2.13.3",
+ "@parcel/types-internal": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "peerDependencies": {
+ "@parcel/core": "^2.13.3"
+ }
+ },
+ "node_modules/@swc/core": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.10.12.tgz",
+ "integrity": "sha512-+iUL0PYpPm6N9AdV1wvafakvCqFegQus1aoEDxgFsv3/uNVNIyRaupf/v/Zkp5hbep2EzhtoJR0aiJIzDbXWHg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3",
+ "@swc/types": "^0.1.17"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/swc"
+ },
+ "optionalDependencies": {
+ "@swc/core-darwin-arm64": "1.10.12",
+ "@swc/core-darwin-x64": "1.10.12",
+ "@swc/core-linux-arm-gnueabihf": "1.10.12",
+ "@swc/core-linux-arm64-gnu": "1.10.12",
+ "@swc/core-linux-arm64-musl": "1.10.12",
+ "@swc/core-linux-x64-gnu": "1.10.12",
+ "@swc/core-linux-x64-musl": "1.10.12",
+ "@swc/core-win32-arm64-msvc": "1.10.12",
+ "@swc/core-win32-ia32-msvc": "1.10.12",
+ "@swc/core-win32-x64-msvc": "1.10.12"
+ },
+ "peerDependencies": {
+ "@swc/helpers": "*"
+ },
+ "peerDependenciesMeta": {
+ "@swc/helpers": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@swc/core-darwin-arm64": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.10.12.tgz",
+ "integrity": "sha512-pOANQegUTAriW7jq3SSMZGM5l89yLVMs48R0F2UG6UZsH04SiViCnDctOGlA/Sa++25C+rL9MGMYM1jDLylBbg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-darwin-x64": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.10.12.tgz",
+ "integrity": "sha512-m4kbpIDDsN1FrwfNQMU+FTrss356xsXvatLbearwR+V0lqOkjLBP0VmRvQfHEg+uy13VPyrT9gj4HLoztlci7w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm-gnueabihf": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.10.12.tgz",
+ "integrity": "sha512-OY9LcupgqEu8zVK+rJPes6LDJJwPDmwaShU96beTaxX2K6VrXbpwm5WbPS/8FfQTsmpnuA7dCcMPUKhNgmzTrQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-gnu": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.10.12.tgz",
+ "integrity": "sha512-nJD587rO0N4y4VZszz3xzVr7JIiCzSMhEMWnPjuh+xmPxDBz0Qccpr8xCr1cSxpl1uY7ERkqAGlKr6CwoV5kVg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-arm64-musl": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.10.12.tgz",
+ "integrity": "sha512-oqhSmV+XauSf0C//MoQnVErNUB/5OzmSiUzuazyLsD5pwqKNN+leC3JtRQ/QVzaCpr65jv9bKexT9+I2Tt3xDw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-gnu": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.10.12.tgz",
+ "integrity": "sha512-XldSIHyjD7m1Gh+/8rxV3Ok711ENLI420CU2EGEqSe3VSGZ7pHJvJn9ZFbYpWhsLxPqBYMFjp3Qw+J6OXCPXCA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-linux-x64-musl": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.10.12.tgz",
+ "integrity": "sha512-wvPXzJxzPgTqhyp1UskOx1hRTtdWxlyFD1cGWOxgLsMik0V9xKRgqKnMPv16Nk7L9xl6quQ6DuUHj9ID7L3oVw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-arm64-msvc": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.10.12.tgz",
+ "integrity": "sha512-TUYzWuu1O7uyIcRfxdm6Wh1u+gNnrW5M1DUgDOGZLsyQzgc2Zjwfh2llLhuAIilvCVg5QiGbJlpibRYJ/8QGsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-ia32-msvc": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.10.12.tgz",
+ "integrity": "sha512-4Qrw+0Xt+Fe2rz4OJ/dEPMeUf/rtuFWWAj/e0vL7J5laUHirzxawLRE5DCJLQTarOiYR6mWnmadt9o3EKzV6Xg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/core-win32-x64-msvc": {
+ "version": "1.10.12",
+ "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.10.12.tgz",
+ "integrity": "sha512-YiloZXLW7rUxJpALwHXaGjVaAEn+ChoblG7/3esque+Y7QCyheoBUJp2DVM1EeVA43jBfZ8tvYF0liWd9Tpz1A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "Apache-2.0 AND MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@swc/counter": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
+ "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.5.15",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+ "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
+ "node_modules/@swc/types": {
+ "version": "0.1.17",
+ "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.17.tgz",
+ "integrity": "sha512-V5gRru+aD8YVyCOMAjMpWR1Ui577DD5KSJsHP8RAxopAH22jFz6GZd/qxqjO6MJHQhcsjvjOFXyDhyLQUnMveQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@swc/counter": "^0.1.3"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/base-x": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz",
+ "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.24.4",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
+ "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001688",
+ "electron-to-chromium": "^1.5.73",
+ "node-releases": "^2.0.19",
+ "update-browserslist-db": "^1.1.1"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001696",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz",
+ "integrity": "sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chrome-trace-event": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
+ "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
+ "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/cosmiconfig": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
+ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.4.7",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+ "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/dotenv-expand": {
+ "version": "11.0.7",
+ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz",
+ "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dotenv": "^16.4.5"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.90",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.90.tgz",
+ "integrity": "sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/get-port": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz",
+ "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/htmlnano": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/htmlnano/-/htmlnano-2.1.1.tgz",
+ "integrity": "sha512-kAERyg/LuNZYmdqgCdYvugyLWNFAm8MWXpQMz1pLpetmCbFwoMxvkSoaAMlFrOC4OKTWI4KlZGT/RsNxg4ghOw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cosmiconfig": "^9.0.0",
+ "posthtml": "^0.16.5",
+ "timsort": "^0.3.0"
+ },
+ "peerDependencies": {
+ "cssnano": "^7.0.0",
+ "postcss": "^8.3.11",
+ "purgecss": "^6.0.0",
+ "relateurl": "^0.2.7",
+ "srcset": "5.0.1",
+ "svgo": "^3.0.2",
+ "terser": "^5.10.0",
+ "uncss": "^0.17.3"
+ },
+ "peerDependenciesMeta": {
+ "cssnano": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ },
+ "purgecss": {
+ "optional": true
+ },
+ "relateurl": {
+ "optional": true
+ },
+ "srcset": {
+ "optional": true
+ },
+ "svgo": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "uncss": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/htmlparser2": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
+ "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
+ "dev": true,
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.1.0",
+ "entities": "^4.5.0"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-json": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
+ "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.1.tgz",
+ "integrity": "sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.29.1",
+ "lightningcss-darwin-x64": "1.29.1",
+ "lightningcss-freebsd-x64": "1.29.1",
+ "lightningcss-linux-arm-gnueabihf": "1.29.1",
+ "lightningcss-linux-arm64-gnu": "1.29.1",
+ "lightningcss-linux-arm64-musl": "1.29.1",
+ "lightningcss-linux-x64-gnu": "1.29.1",
+ "lightningcss-linux-x64-musl": "1.29.1",
+ "lightningcss-win32-arm64-msvc": "1.29.1",
+ "lightningcss-win32-x64-msvc": "1.29.1"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.1.tgz",
+ "integrity": "sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.1.tgz",
+ "integrity": "sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.1.tgz",
+ "integrity": "sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.1.tgz",
+ "integrity": "sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.1.tgz",
+ "integrity": "sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.1.tgz",
+ "integrity": "sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.1.tgz",
+ "integrity": "sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.1.tgz",
+ "integrity": "sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.1.tgz",
+ "integrity": "sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.29.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.1.tgz",
+ "integrity": "sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lmdb": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.8.5.tgz",
+ "integrity": "sha512-9bMdFfc80S+vSldBmG3HOuLVHnxRdNTlpzR6QDnzqCQtCzGUEAGTzBKYMeIM+I/sU4oZfgbcbS7X7F65/z/oxQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "msgpackr": "^1.9.5",
+ "node-addon-api": "^6.1.0",
+ "node-gyp-build-optional-packages": "5.1.1",
+ "ordered-binary": "^1.4.1",
+ "weak-lru-cache": "^1.2.2"
+ },
+ "bin": {
+ "download-lmdb-prebuilds": "bin/download-prebuilds.js"
+ },
+ "optionalDependencies": {
+ "@lmdb/lmdb-darwin-arm64": "2.8.5",
+ "@lmdb/lmdb-darwin-x64": "2.8.5",
+ "@lmdb/lmdb-linux-arm": "2.8.5",
+ "@lmdb/lmdb-linux-arm64": "2.8.5",
+ "@lmdb/lmdb-linux-x64": "2.8.5",
+ "@lmdb/lmdb-win32-x64": "2.8.5"
+ }
+ },
+ "node_modules/lmdb/node_modules/node-addon-api": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz",
+ "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/msgpackr": {
+ "version": "1.11.2",
+ "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.2.tgz",
+ "integrity": "sha512-F9UngXRlPyWCDEASDpTf6c9uNhGPTqnTeLVt7bN+bU1eajoR/8V9ys2BRaV5C/e5ihE6sJ9uPIKaYt6bFuO32g==",
+ "dev": true,
+ "license": "MIT",
+ "optionalDependencies": {
+ "msgpackr-extract": "^3.0.2"
+ }
+ },
+ "node_modules/msgpackr-extract": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
+ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "node-gyp-build-optional-packages": "5.2.2"
+ },
+ "bin": {
+ "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
+ },
+ "optionalDependencies": {
+ "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
+ }
+ },
+ "node_modules/msgpackr-extract/node_modules/detect-libc": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+ "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
+ "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^2.0.1"
+ },
+ "bin": {
+ "node-gyp-build-optional-packages": "bin.js",
+ "node-gyp-build-optional-packages-optional": "optional.js",
+ "node-gyp-build-optional-packages-test": "build-test.js"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-gyp-build-optional-packages": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz",
+ "integrity": "sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.1"
+ },
+ "bin": {
+ "node-gyp-build-optional-packages": "bin.js",
+ "node-gyp-build-optional-packages-optional": "optional.js",
+ "node-gyp-build-optional-packages-test": "build-test.js"
+ }
+ },
+ "node_modules/node-gyp-build-optional-packages/node_modules/detect-libc": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+ "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nullthrows": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz",
+ "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ordered-binary": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.5.3.tgz",
+ "integrity": "sha512-oGFr3T+pYdTGJ+YFEILMpS3es+GiIbs9h/XQrclBXUtd44ey7XwfsMzM31f64I1SQOawDoDr/D823kNCADI8TA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/parcel": {
+ "version": "2.13.3",
+ "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.13.3.tgz",
+ "integrity": "sha512-8GrC8C7J8mwRpAlk7EJ7lwdFTbCN+dcXH2gy5AsEs9pLfzo9wvxOTx6W0fzSlvCOvZOita+8GdfYlGfEt0tRgA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/config-default": "2.13.3",
+ "@parcel/core": "2.13.3",
+ "@parcel/diagnostic": "2.13.3",
+ "@parcel/events": "2.13.3",
+ "@parcel/feature-flags": "2.13.3",
+ "@parcel/fs": "2.13.3",
+ "@parcel/logger": "2.13.3",
+ "@parcel/package-manager": "2.13.3",
+ "@parcel/reporter-cli": "2.13.3",
+ "@parcel/reporter-dev-server": "2.13.3",
+ "@parcel/reporter-tracer": "2.13.3",
+ "@parcel/utils": "2.13.3",
+ "chalk": "^4.1.2",
+ "commander": "^12.1.0",
+ "get-port": "^4.2.0"
+ },
+ "bin": {
+ "parcel": "lib/bin.js"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/parcel-reporter-static-files-copy": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/parcel-reporter-static-files-copy/-/parcel-reporter-static-files-copy-1.5.3.tgz",
+ "integrity": "sha512-Ukq2SyJYn3GFIPCLamXuQ+2t+0j54llujjOUoRjtmVvfsuGnJDEpMznADeIoKuQDvy0jpxtWzWkQvxqI/j+U4A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/plugin": "^2.0.0-beta.1"
+ },
+ "engines": {
+ "parcel": "^2.0.0-beta.1"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "license": "MIT",
+ "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"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/posthtml": {
+ "version": "0.16.6",
+ "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz",
+ "integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "posthtml-parser": "^0.11.0",
+ "posthtml-render": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/posthtml-parser": {
+ "version": "0.12.1",
+ "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.12.1.tgz",
+ "integrity": "sha512-rYFmsDLfYm+4Ts2Oh4DCDSZPtdC1BLnRXAobypVzX9alj28KGl65dIFtgDY9zB57D0TC4Qxqrawuq/2et1P0GA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "htmlparser2": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/posthtml-render": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
+ "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-json": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/posthtml/node_modules/dom-serializer": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+ "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.0",
+ "entities": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/posthtml/node_modules/dom-serializer/node_modules/entities": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+ "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/posthtml/node_modules/domhandler": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+ "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/posthtml/node_modules/domutils": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+ "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^1.0.1",
+ "domelementtype": "^2.2.0",
+ "domhandler": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/posthtml/node_modules/entities": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
+ "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/posthtml/node_modules/htmlparser2": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
+ "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
+ "dev": true,
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.0.1",
+ "domhandler": "^4.2.2",
+ "domutils": "^2.8.0",
+ "entities": "^3.0.1"
+ }
+ },
+ "node_modules/posthtml/node_modules/posthtml-parser": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
+ "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "htmlparser2": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/react-error-overlay": {
+ "version": "6.0.9",
+ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
+ "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/react-refresh": {
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
+ "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz",
+ "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/srcset": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/srcset/-/srcset-5.0.1.tgz",
+ "integrity": "sha512-/P1UYbGfJVlxZag7aABNRrulEXAwCSDo7fklafOQrantuPTDmYgijJMks2zusPCVzgW9+4P69mq7w6pYuZpgxw==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/term-size": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz",
+ "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/timsort": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
+ "integrity": "sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
+ "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/utility-types": {
+ "version": "3.11.0",
+ "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz",
+ "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/weak-lru-cache": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz",
+ "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==",
+ "dev": true,
+ "license": "MIT"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..6ff84628
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "javascript-snake",
+ "version": "1.0.0",
+ "description": "JavaScript Snake
By Patrick Gillespie
License: MIT
http://patorjk.com/games/snake",
+ "scripts": {
+ "start": "parcel src/index.html --open",
+ "build": "parcel build src/index.html",
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/patorjk/JavaScript-Snake.git"
+ },
+ "author": "",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/patorjk/JavaScript-Snake/issues"
+ },
+ "homepage": "https://github.com/patorjk/JavaScript-Snake#readme",
+ "devDependencies": {
+ "parcel": "^2.13.3",
+ "parcel-reporter-static-files-copy": "^1.5.3"
+ },
+ "staticFiles": {
+ "staticPath": "src/css",
+ "staticOutPath": "css"
+ }
+}
diff --git a/src/ai-example.html b/src/ai-example.html
new file mode 100644
index 00000000..d3ca29d7
--- /dev/null
+++ b/src/ai-example.html
@@ -0,0 +1,148 @@
+
+
+
+
+
+ JavaScript Snake - AI Example
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/css/Senura-snake.css b/src/css/Senura-snake.css
new file mode 100644
index 00000000..2102a783
--- /dev/null
+++ b/src/css/Senura-snake.css
@@ -0,0 +1,146 @@
+/*
+JavaScript Snake
+By Patrick Gillespie
+http://patorjk.com/games/snake
+*/
+
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: #000000;
+}
+
+.snake-toolbar {
+ color: #847a87;
+}
+
+#game-area {
+ margin: 10px;
+ padding: 0px;
+}
+
+#game-area:focus {
+ outline: none;
+}
+
+#mode-wrapper {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #f6f0f7;
+}
+
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: #605d61;
+}
+
+a.snake-link:hover {
+ color: #a500d6;
+}
+
+.snake-pause-screen {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: #ffffff;
+ color: #938996;
+}
+
+.snake-panel-component {
+ position: absolute;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #cf6d6d;
+ text-align: center;
+ background-color: #550b70;
+ padding: 8px;
+ margin: 0px;
+}
+
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #eddff2;
+ position: absolute;
+ border: 0px solid black;
+ background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+ background-image: url("src/css/images/dark-snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("src/css/images/dead-dark-snakeblock.png");
+}
+
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: black;
+ border: 2px solid #000000;
+ position: absolute;
+}
+
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: #fcfcfc;
+ border: 3px solid black;
+}
+
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ background-color: #3e2e44;
+ position: relative;
+}
+
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: black;
+ color: #ab00de;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: black;
+ color: #ab00de;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/src/css/black-snake.css b/src/css/black-snake.css
new file mode 100644
index 00000000..a92710b5
--- /dev/null
+++ b/src/css/black-snake.css
@@ -0,0 +1,142 @@
+/*
+JavaScript Snake
+By Patrick Gillespie
+http://patorjk.com/games/snake
+*/
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: black;
+ color: white;
+}
+
+#game-area {
+ margin: 10px;
+ padding: 0px;
+}
+
+#mode-wrapper {
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+}
+
+#game-area:focus {
+ outline: none;
+}
+
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: #fcfc54;
+}
+
+a.snake-link:hover {
+ color: #ffff54;
+}
+
+.snake-pause-screen {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: black;
+ color: white;
+}
+
+.snake-panel-component {
+ position: absolute;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #ffffff;
+ text-align: center;
+ padding: 8px;
+ margin: 0px;
+}
+
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #ff0000;
+ position: absolute;
+ border: 0px solid #000080;
+ background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+ background-image: url("src/cssss/images/snakeblock.png"),
+ url("src/css/images/snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("src/cssss/images/deadblock.png"),
+ url("src/css/images/deadblock.png");
+}
+
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: aqua;
+ border: 0px solid #000080;
+ position: absolute;
+}
+
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: purple;
+ border: 0px solid purple;
+}
+
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ position: relative;
+}
+
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/src/css/dark-snake.css b/src/css/dark-snake.css
new file mode 100644
index 00000000..16388e41
--- /dev/null
+++ b/src/css/dark-snake.css
@@ -0,0 +1,146 @@
+/*
+JavaScript Snake
+By Patrick Gillespie
+http://patorjk.com/games/snake
+*/
+
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: #3e2e44;
+}
+
+.snake-toolbar {
+ color: #938996;
+}
+
+#game-area {
+ margin: 10px;
+ padding: 0px;
+}
+
+#game-area:focus {
+ outline: none;
+}
+
+#mode-wrapper {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #938996;
+}
+
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: #938996;
+}
+
+a.snake-link:hover {
+ color: #938996;
+}
+
+.snake-pause-screen {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: #3e2e44;
+ color: #938996;
+}
+
+.snake-panel-component {
+ position: absolute;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #938996;
+ text-align: center;
+ background-color: #3e2e44;
+ padding: 8px;
+ margin: 0px;
+}
+
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #3e2e44;
+ position: absolute;
+ border: 0px solid black;
+ background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+ background-image: url("src/css/images/dark-snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("src/css/images/dead-dark-snakeblock.png");
+}
+
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: black;
+ border: 2px solid #3e2e44;
+ position: absolute;
+}
+
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: #312e44;
+ border: 3px solid black;
+}
+
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ background-color: #3e2e44;
+ position: relative;
+}
+
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: black;
+ color: #938996;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: black;
+ color: #938996;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/src/css/green-snake.css b/src/css/green-snake.css
new file mode 100644
index 00000000..9cd114c5
--- /dev/null
+++ b/src/css/green-snake.css
@@ -0,0 +1,147 @@
+/*
+JavaScript Snake
+By Patrick Gillespie
+http://patorjk.com/games/snake
+*/
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: darkgreen;
+}
+
+.snake-toolbar {
+ background-color: rgba(255, 255, 255, 0.4);
+ border-radius: 10px;
+}
+
+#game-area {
+ margin: 10px;
+ padding: 0px;
+ background-color: lightgreen;
+}
+
+#mode-wrapper {
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+}
+
+#game-area:focus {
+ outline: none;
+}
+
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: black;
+}
+
+a.snake-link:hover {
+ color: #ffff54;
+}
+
+.snake-pause-screen {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: black;
+ color: white;
+}
+
+.snake-panel-component {
+ position: absolute;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: black;
+ text-align: center;
+ background-color: white;
+ padding: 8px;
+ margin: 0px;
+}
+
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #ff0000;
+ position: absolute;
+ border: 0px solid #000080;
+ background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+ background-image: url("src/css/images/snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("src/css/images/deadblock.png");
+}
+
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: black;
+ border: 0px solid #000080;
+ position: absolute;
+}
+
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: white;
+ border: 0px solid #0000a8;
+}
+
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ background-color: #fc5454;
+ position: relative;
+}
+
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/src/css/head-snake.css b/src/css/head-snake.css
new file mode 100644
index 00000000..0e7daf95
--- /dev/null
+++ b/src/css/head-snake.css
@@ -0,0 +1,148 @@
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: rgb(0, 0, 0);
+}
+
+#game-area {
+ margin: 10px;
+ padding: 0px;
+}
+
+#mode-wrapper {
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+}
+
+#game-area:focus {
+ outline: none;
+}
+
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: #fcfc54;
+}
+
+a.snake-link:hover {
+ color: #ffff54;
+}
+
+.snake-pause-screen {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: black;
+ color: white;
+}
+
+.snake-panel-component {
+ position: absolute;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #ffffff;
+ text-align: center;
+ padding: 8px;
+ margin: 0px;
+}
+
+#snake-snakehead-alive {
+ background-image: url("src/css/images/green-head-snakeblock.png");
+ margin: 0px;
+ padding: 0px;
+ background-color: rgb(10, 173, 10);
+ position: absolute;
+ border: 0px solid #000080;
+ background-repeat: no-repeat;
+ border-radius: 4px;
+}
+
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #ff0000;
+ position: absolute;
+ border: 0px solid #000080;
+ background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+ background-image: url("src/css/images/green-body-snakeblock.png"),
+ url("src/css/images/green-body-snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("src/css/images/deadblock.png"),
+ url("src/css/images/deadblock.png");
+}
+
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: rgb(182, 11, 11);
+ border: 0px solid #000080;
+ position: absolute;
+ border-radius: 6px;
+}
+
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: rgb(245, 245, 220);
+ border: 0px solid #0000a8;
+}
+
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ position: relative;
+}
+
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/css/images/Thumbs.db b/src/css/images/Thumbs.db
similarity index 100%
rename from css/images/Thumbs.db
rename to src/css/images/Thumbs.db
diff --git a/src/css/images/dark-snakeblock.png b/src/css/images/dark-snakeblock.png
new file mode 100644
index 00000000..66c4f1c2
Binary files /dev/null and b/src/css/images/dark-snakeblock.png differ
diff --git a/src/css/images/dead-dark-snakeblock.png b/src/css/images/dead-dark-snakeblock.png
new file mode 100644
index 00000000..63302e51
Binary files /dev/null and b/src/css/images/dead-dark-snakeblock.png differ
diff --git a/css/images/deadblock.png b/src/css/images/deadblock.png
similarity index 100%
rename from css/images/deadblock.png
rename to src/css/images/deadblock.png
diff --git a/css/images/deadblock_border.png b/src/css/images/deadblock_border.png
similarity index 100%
rename from css/images/deadblock_border.png
rename to src/css/images/deadblock_border.png
diff --git a/src/css/images/favicon.png b/src/css/images/favicon.png
new file mode 100644
index 00000000..ccbbc5d8
Binary files /dev/null and b/src/css/images/favicon.png differ
diff --git a/src/css/images/green-body-snakeblock.png b/src/css/images/green-body-snakeblock.png
new file mode 100644
index 00000000..fa9d23de
Binary files /dev/null and b/src/css/images/green-body-snakeblock.png differ
diff --git a/src/css/images/green-head-snakeblock.png b/src/css/images/green-head-snakeblock.png
new file mode 100644
index 00000000..5d235cd5
Binary files /dev/null and b/src/css/images/green-head-snakeblock.png differ
diff --git a/src/css/images/matrix-food-block.png b/src/css/images/matrix-food-block.png
new file mode 100644
index 00000000..5e3ef68b
Binary files /dev/null and b/src/css/images/matrix-food-block.png differ
diff --git a/src/css/images/matrix-snake-block.png b/src/css/images/matrix-snake-block.png
new file mode 100644
index 00000000..8416cc80
Binary files /dev/null and b/src/css/images/matrix-snake-block.png differ
diff --git a/src/css/images/neon-body-snakeblock.png b/src/css/images/neon-body-snakeblock.png
new file mode 100644
index 00000000..d66f7717
Binary files /dev/null and b/src/css/images/neon-body-snakeblock.png differ
diff --git a/src/css/images/neon-dead-snakeblock.png b/src/css/images/neon-dead-snakeblock.png
new file mode 100644
index 00000000..55da41ab
Binary files /dev/null and b/src/css/images/neon-dead-snakeblock.png differ
diff --git a/css/images/snakeblock.png b/src/css/images/snakeblock.png
similarity index 100%
rename from css/images/snakeblock.png
rename to src/css/images/snakeblock.png
diff --git a/src/css/light-snake.css b/src/css/light-snake.css
new file mode 100644
index 00000000..db0be890
--- /dev/null
+++ b/src/css/light-snake.css
@@ -0,0 +1,127 @@
+/*
+JavaScript Snake
+By Patrick Gillespie
+http://patorjk.com/games/snake
+*/
+
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: #f73378;
+}
+#game-area {
+ margin: 10px;
+ padding: 0px;
+}
+
+#mode-wrapper {
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+}
+#game-area:focus {
+ outline: none;
+}
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: #fcfc54;
+}
+a.snake-link:hover {
+ color: #ffff54;
+}
+.snake-pause-screen {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: black;
+ color: white;
+}
+.snake-panel-component {
+ position: absolute;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #ffffff;
+ text-align: center;
+ padding: 8px;
+ margin: 0px;
+}
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #ff0000;
+ position: absolute;
+ border: 0px solid #000080;
+ background-repeat: no-repeat;
+}
+.snake-snakebody-alive {
+ background-image: url("src/css/images/snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("src/css/images/deadblock.png");
+}
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #6cfd6a;
+ border: 0px solid #000080;
+ position: absolute;
+}
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: #ab003c;
+ border: 0px solid #ab003c;
+}
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ position: relative;
+}
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/src/css/main-snake.css b/src/css/main-snake.css
new file mode 100755
index 00000000..7938bf34
--- /dev/null
+++ b/src/css/main-snake.css
@@ -0,0 +1,140 @@
+/*
+JavaScript Snake
+By Patrick Gillespie
+http://patorjk.com/games/snake
+*/
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: #fc5454;
+}
+
+#game-area {
+ margin: 10px;
+ padding: 0px;
+}
+
+#mode-wrapper {
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+}
+
+#game-area:focus {
+ outline: none;
+}
+
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: #fcfc54;
+}
+
+a.snake-link:hover {
+ color: #ffff54;
+}
+
+.snake-pause-screen {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: black;
+ color: white;
+}
+
+.snake-panel-component {
+ position: absolute;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #ffffff;
+ text-align: center;
+ padding: 8px;
+ margin: 0px;
+}
+
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #ff0000;
+ position: absolute;
+ border: 0px solid #000080;
+ background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+ background-image: url("./images/snakeblock.png"),
+ url("./images/snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("./images/deadblock.png"), url("./images/deadblock.png");
+}
+
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #ff0000;
+ border: 0px solid #000080;
+ position: absolute;
+}
+
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: #0000a8;
+ border: 0px solid #0000a8;
+}
+
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ position: relative;
+}
+
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #000000;
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/src/css/matrix-snake.css b/src/css/matrix-snake.css
new file mode 100644
index 00000000..643d6960
--- /dev/null
+++ b/src/css/matrix-snake.css
@@ -0,0 +1,134 @@
+body {
+margin:0px;
+padding:0px;
+background-color: #00ff11;
+}
+
+#game-area {
+margin:10px;
+padding:0px;
+background-color: #00ff11;
+}
+
+#mode-wrapper {
+color: #000000;
+font-family: Verdana, arial, helvetica, sans-serif;
+font-size: 14px;
+
+}
+
+#game-area:focus { outline: none; }
+
+a.snake-link, a.snake-link:link, a.snake-link:visited {
+color: #FCFC54;
+}
+
+a.snake-link:hover {
+color: #FfFf54;
+}
+
+.snake-pause-screen {
+font-family: Verdana, arial, helvetica, sans-serif;
+font-size: 14px;
+position:absolute;
+width:300px;
+height:80px;
+text-align:center;
+top:50%;
+left:50%;
+margin-top:-40px;
+margin-left:-150px;
+display:none;
+background-color:black;
+color:white;
+}
+
+.snake-panel-component {
+position: absolute;
+font-family: Verdana, arial, helvetica, sans-serif;
+font-size: 14px;
+color: #000000;
+text-align: center;
+background-color: #00ff11;
+padding: 8px;
+margin: 0px;
+}
+
+.snake-snakebody-block {
+margin: 0px;
+padding: 0px;
+background-color: #FF0000;
+position: absolute;
+border: 0px solid #000080;
+background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+background-image: url('src/css/images/matrix-snake-block.png');
+}
+.snake-snakebody-dead {
+background-image: url('src/css/images/deadblock.png');
+}
+
+.snake-food-block {
+margin: 0px;
+padding: 0px;
+background-color: #FF0000;
+border: 0px solid #000080;
+position: absolute;
+background-image: url("src/css/images/matrix-food-block.png")
+}
+
+.snake-playing-field {
+margin: 0px;
+padding: 0px;
+position: absolute;
+background-color: #000000;
+border: 0px solid #000000;
+}
+
+.snake-game-container {
+margin: 0px;
+padding: 0px;
+border-width: 0px;
+border-style: none;
+zoom: 1;
+background-color: #00ff11;
+position: relative;
+}
+
+.snake-welcome-dialog {
+padding: 8px;
+margin: 0px;
+background-color: #000000;
+color: #00ff11;
+font-family: Verdana, arial, helvetica, sans-serif;
+font-size: 14px;
+position: absolute;
+top: 50%;
+left: 50%;
+width: 300px;
+/height: 150px;/
+margin-top: -100px;
+margin-left: -158px;
+text-align: center;
+display: block;
+}
+
+.snake-try-again-dialog, .snake-win-dialog {
+padding: 8px;
+margin: 0px;
+background-color: #000000;
+color: #ff0000;
+font-family: Verdana, arial, helvetica, sans-serif;
+font-size: 14px;
+position: absolute;
+top: 50%;
+left: 50%;
+width: 300px;
+height: 100px;
+margin-top: -75px;
+margin-left: -158px;
+text-align: center;
+display: none;
+}
diff --git a/src/css/neon-snake.css b/src/css/neon-snake.css
new file mode 100644
index 00000000..49591510
--- /dev/null
+++ b/src/css/neon-snake.css
@@ -0,0 +1,145 @@
+/*
+JavaScript Snake
+By Patrick Gillespie
+http://patorjk.com/games/snake
+*/
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: #000000;
+}
+
+.snake-toolbar {
+ color: #ffffff;
+}
+
+#game-area {
+ margin: 10px;
+ padding: 0px;
+}
+
+#mode-wrapper {
+ color: #ffffff;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+}
+
+#game-area:focus {
+ outline: none;
+}
+
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: #00ffe0;
+}
+
+a.snake-link:hover {
+ color: #0fff00;
+}
+
+.snake-pause-screen {
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: #0fff00;
+ color: #000000;
+}
+
+.snake-panel-component {
+ position: absolute;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ color: #ffffff;
+ text-align: center;
+ padding: 8px;
+ margin: 0px;
+}
+
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #ff0000;
+ position: absolute;
+ border: 0px solid #000080;
+ background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+ background-image: url("src/css/images/neon-body-snakeblock.png"),
+ url("src/cssss/images/neon-body-snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("src/css/images/neon-dead-snakeblock.png"),
+ url("src/cssss/images/neon-dead-snakeblock.png");
+}
+
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: #ff0000;
+ border: 0px solid #000080;
+ position: absolute;
+}
+
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: #00ffd4;
+ border: 0px solid #0000a8;
+}
+
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ position: relative;
+}
+
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #0fff00;
+ color: #000000;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: #0fff00;
+ color: #000000;
+ font-family: Verdana, arial, helvetica, sans-serif;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/src/css/teal-snake.css b/src/css/teal-snake.css
new file mode 100644
index 00000000..ac06471a
--- /dev/null
+++ b/src/css/teal-snake.css
@@ -0,0 +1,148 @@
+/*
+JavaScript Snake
+By Patrick Gillespie
+http://patorjk.com/games/snake
+*/
+@import url("https://fonts.googleapis.com/css2?family=Electrolize&display=swap");
+
+body {
+ margin: 0px;
+ padding: 0px;
+ background-color: teal;
+}
+
+.snake-toolbar {
+ font-family: Electrolize;
+ color: white;
+}
+
+#game-area {
+ margin: 10px;
+ padding: 0px;
+}
+
+#game-area:focus {
+ outline: none;
+}
+
+#mode-wrapper {
+ font-family: Electrolize;
+ font-size: 14px;
+ color: whitesmoke;
+}
+
+a.snake-link,
+a.snake-link:link,
+a.snake-link:visited {
+ color: white;
+}
+
+a.snake-link:hover {
+ color: white;
+}
+
+.snake-pause-screen {
+ font-family: Electrolize;
+ font-size: 16px;
+ position: absolute;
+ width: 300px;
+ height: 80px;
+ text-align: center;
+ top: 50%;
+ left: 50%;
+ margin-top: -40px;
+ margin-left: -150px;
+ display: none;
+ background-color: #3e2e44;
+ color: whitesmoke;
+}
+
+.snake-panel-component {
+ position: absolute;
+ font-family: Electrolize;
+ font-size: 16px;
+ color: #938996;
+ text-align: center;
+ background-color: #3e2e44;
+ padding: 8px;
+ margin: 0px;
+}
+
+.snake-snakebody-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: orange;
+ position: absolute;
+ border: 0px solid black;
+ background-repeat: no-repeat;
+}
+
+.snake-snakebody-alive {
+ background-image: url("src/css/images/snakeblock.png");
+}
+.snake-snakebody-dead {
+ background-image: url("src/css/images/dead-dark-snakeblock.png");
+}
+
+.snake-food-block {
+ margin: 0px;
+ padding: 0px;
+ background-color: red;
+ border: 2px solid black;
+ position: absolute;
+}
+
+.snake-playing-field {
+ margin: 0px;
+ padding: 0px;
+ position: absolute;
+ background-color: rgb(0, 180, 180);
+ border: 3px solid black;
+}
+
+.snake-game-container {
+ margin: 0px;
+ padding: 0px;
+ border-width: 0px;
+ border-style: none;
+ zoom: 1;
+ background-color: #3e2e44;
+ position: relative;
+}
+
+.snake-welcome-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: black;
+ color: whitesmoke;
+ font-family: Electrolize;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ /*height: 150px;*/
+ margin-top: -100px;
+ margin-left: -158px;
+ text-align: center;
+ display: block;
+}
+
+.snake-try-again-dialog,
+.snake-win-dialog {
+ padding: 8px;
+ margin: 0px;
+ background-color: black;
+ color: whitesmoke;
+ font-family: Electrolize;
+ font-size: 16px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 300px;
+ height: 100px;
+ margin-top: -75px;
+ margin-left: -158px;
+ text-align: center;
+ display: none;
+}
diff --git a/src/index.html b/src/index.html
new file mode 100755
index 00000000..03dc6b10
--- /dev/null
+++ b/src/index.html
@@ -0,0 +1,151 @@
+
+
+
+
+
+ JavaScript Snake
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/js/ai-init.js b/src/js/ai-init.js
new file mode 100644
index 00000000..5f3e46bb
--- /dev/null
+++ b/src/js/ai-init.js
@@ -0,0 +1,58 @@
+const mySnakeBoard = new SNAKE.Board({
+ boardContainer: "game-area",
+ fullScreen: true,
+ premoveOnPause: false,
+ moveSnakeWithAI: ({
+ grid,
+ snakeHead,
+ currentDirection,
+ isFirstGameMove,
+ setDirection,
+ }) => {
+
+ /*
+ Direction:
+ 0
+ 3 1
+ 2
+ */
+
+ // This is NOT a real hamiltonian cycle. It misses some values, I'm just including this here as an example of
+ // a look-up type table that you could do.
+ const hamiltonianCycleGrid = [
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0],
+ [0, 0, 2, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 0],
+ [0, 0, 2, 0, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0],
+ [0, 0, 2, 0, 2, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0],
+ [0, 0, 3, 0, 3, 3, 3, 3, 0, 3, 0, 3, 0, 3, 0],
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
+ ]
+
+ console.log(JSON.parse(JSON.stringify(grid)))
+ console.log(snakeHead, currentDirection)
+
+ const newDirection = hamiltonianCycleGrid[snakeHead.row][snakeHead.col];
+ console.log(newDirection);
+ setDirection(newDirection);
+ },
+ onLengthUpdate: (length) => {
+ console.log(`Length: ${length}`);
+ },
+ onPauseToggle: (isPaused) => {
+ console.log(`Is paused: ${isPaused}`);
+ },
+ onInit: (params) => {
+ console.log("init!");
+ console.log(params);
+ params.startAIGame();
+ },
+ onWin: (params) => {
+ console.log("win!");
+ //params.startAIGame();
+ },
+ onDeath: (params) => {
+ console.log("dead!");
+ //params.startAIGame();
+ },
+});
diff --git a/src/js/init.js b/src/js/init.js
new file mode 100644
index 00000000..daddd8b8
--- /dev/null
+++ b/src/js/init.js
@@ -0,0 +1,21 @@
+const mySnakeBoard = new SNAKE.Board({
+ boardContainer: "game-area",
+ fullScreen: true,
+ premoveOnPause: false,
+ onLengthUpdate: (length) => {
+ console.log(`Length: ${length}`);
+ },
+ onPauseToggle: (isPaused) => {
+ console.log(`Is paused: ${isPaused}`);
+ },
+ onInit: (params) => {
+ console.log("init!");
+ console.log(params);
+ },
+ onWin: () => {
+ console.log("wn!");
+ },
+ onDeath: () => {
+ console.log("dead!");
+ },
+});
diff --git a/src/js/snake.js b/src/js/snake.js
new file mode 100644
index 00000000..6232e8d9
--- /dev/null
+++ b/src/js/snake.js
@@ -0,0 +1,1411 @@
+/*
+JavaScript Snake
+First version by Patrick Gillespie - I've since merged in a good number of github pull requests
+http://patorjk.com/games/snake
+*/
+
+/**
+ * @module Snake
+ * @class SNAKE
+ */
+
+// this will allow us to access the game in other JS files when the app is loaded up in a codesandbox.com sandbox, that's the only reason it's here
+if (!window.SNAKE) {
+ window.SNAKE = {};
+}
+
+/*
+ Direction explained (0 = up, etc etc)
+ 0
+ 3 1
+ 2
+*/
+const MOVE_NONE = -1;
+const MOVE_UP = 0;
+const MOVE_LEFT = 3;
+const MOVE_DOWN = 2;
+const MOVE_RIGHT = 1;
+
+const MIN_SNAKE_SPEED = 25;
+const RUSH_INCR = 5;
+
+const DEFAULT_SNAKE_SPEED = 80;
+
+const BOARD_NOT_READY = 0;
+const BOARD_READY = 1;
+const BOARD_IN_PLAY = 2;
+
+const HIGH_SCORE_KEY = "jsSnakeHighScore";
+
+/**
+ * @method addEventListener
+ * @param {Object} obj The object to add an event listener to.
+ * @param {String} event The event to listen for.
+ * @param {Function} funct The function to execute when the event is triggered.
+ * @param {Boolean} evtCapturing True to do event capturing, false to do event bubbling.
+ */
+SNAKE.addEventListener = (function () {
+ if (window.addEventListener) {
+ return function (obj, event, funct, evtCapturing) {
+ obj.addEventListener(event, funct, evtCapturing);
+ };
+ } else if (window.attachEvent) {
+ return function (obj, event, funct) {
+ obj.attachEvent("on" + event, funct);
+ };
+ }
+})();
+
+/**
+ * @method removeEventListener
+ * @param {Object} obj The object to remove an event listener from.
+ * @param {String} event The event that was listened for.
+ * @param {Function} funct The function that was executed when the event is triggered.
+ * @param {Boolean} evtCapturing True if event capturing was done, false otherwise.
+ */
+
+SNAKE.removeEventListener = (function () {
+ if (window.removeEventListener) {
+ return function (obj, event, funct, evtCapturing) {
+ obj.removeEventListener(event, funct, evtCapturing);
+ };
+ } else if (window.detachEvent) {
+ return function (obj, event, funct) {
+ obj.detachEvent("on" + event, funct);
+ };
+ }
+})();
+
+/**
+ * This class manages the snake which will reside inside of a SNAKE.Board object.
+ * @class Snake
+ * @constructor
+ * @namespace SNAKE
+ * @param {Object} config The configuration object for the class. Contains playingBoard (the SNAKE.Board that this snake resides in), startRow and startCol.
+ */
+SNAKE.Snake =
+ SNAKE.Snake ||
+ (function () {
+ // -------------------------------------------------------------------------
+ // Private static variables and methods
+ // -------------------------------------------------------------------------
+
+ const blockPool = [];
+
+ const SnakeBlock = function () {
+ this.elm = null;
+ this.elmStyle = null;
+ this.row = -1;
+ this.col = -1;
+ this.next = null;
+ this.prev = null;
+ };
+
+ // this function is adapted from the example at http://greengeckodesign.com/blog/2007/07/get-highest-z-index-in-javascript.html
+ function getNextHighestZIndex(myObj) {
+ let highestIndex = 0,
+ currentIndex = 0,
+ ii;
+ for (ii in myObj) {
+ if (myObj[ii].elm.currentStyle) {
+ currentIndex = parseFloat(myObj[ii].elm.style["z-index"], 10);
+ } else if (window.getComputedStyle) {
+ currentIndex = parseFloat(
+ document.defaultView
+ .getComputedStyle(myObj[ii].elm, null)
+ .getPropertyValue("z-index"),
+ 10,
+ );
+ }
+ if (!isNaN(currentIndex) && currentIndex > highestIndex) {
+ highestIndex = currentIndex;
+ }
+ }
+ return highestIndex + 1;
+ }
+
+ // -------------------------------------------------------------------------
+ // Contructor + public and private definitions
+ // -------------------------------------------------------------------------
+
+ /*
+ config options:
+ playingBoard - the SnakeBoard that this snake belongs too.
+ startRow - The row the snake should start on.
+ startCol - The column the snake should start on.
+ moveSnakeWithAI - function to move the snake with AI
+ */
+ return function (config) {
+ if (!config || !config.playingBoard) {
+ return;
+ }
+ if (localStorage[HIGH_SCORE_KEY] === undefined)
+ localStorage.setItem(HIGH_SCORE_KEY, 0);
+
+ // ----- private variables -----
+
+ const me = this;
+ const playingBoard = config.playingBoard;
+ const growthIncr = 5;
+ const columnShift = [0, 1, 0, -1];
+ const rowShift = [-1, 0, 1, 0];
+ let prevNode;
+
+ let lastMove = 1,
+ preMove = MOVE_NONE,
+ isFirstGameMove = true,
+ currentDirection = MOVE_NONE, // 0: up, 1: left, 2: down, 3: right
+ snakeSpeed = DEFAULT_SNAKE_SPEED,
+ isDead = false,
+ isPaused = false;
+
+ const modeDropdown = document.getElementById("selectMode");
+ if (modeDropdown) {
+ modeDropdown.addEventListener("change", function (evt) {
+ evt = evt || {};
+ let val = evt.target
+ ? parseInt(evt.target.value)
+ : DEFAULT_SNAKE_SPEED;
+
+ if (isNaN(val)) {
+ val = DEFAULT_SNAKE_SPEED;
+ } else if (val < MIN_SNAKE_SPEED) {
+ val = DEFAULT_SNAKE_SPEED;
+ }
+
+ snakeSpeed = val;
+
+ setTimeout(function () {
+ document.getElementById("game-area").focus();
+ }, 10);
+ });
+ }
+
+ // ----- public variables -----
+ me.snakeBody = {};
+ me.snakeBody["b0"] = new SnakeBlock(); // create snake head
+ me.snakeBody["b0"].row = config.startRow || 1;
+ me.snakeBody["b0"].col = config.startCol || 1;
+ me.snakeBody["b0"].elm = createSnakeElement();
+ me.snakeBody["b0"].elmStyle = me.snakeBody["b0"].elm.style;
+ playingBoard.getBoardContainer().appendChild(me.snakeBody["b0"].elm);
+ me.snakeBody["b0"].elm.style.left = getLeftPosition(me.snakeBody["b0"]);
+ me.snakeBody["b0"].elm.style.top = getTopPosition(me.snakeBody["b0"]);
+ me.snakeBody["b0"].next = me.snakeBody["b0"];
+ me.snakeBody["b0"].prev = me.snakeBody["b0"];
+
+ me.snakeLength = 1;
+ me.snakeHead = me.snakeBody["b0"];
+ me.snakeTail = me.snakeBody["b0"];
+ me.snakeHead.elm.className = me.snakeHead.elm.className.replace(
+ /\bsnake-snakebody-dead\b/,
+ "",
+ );
+ me.snakeHead.elm.id = "snake-snakehead-alive";
+ me.snakeHead.elm.className += " snake-snakebody-alive";
+
+ // ----- private methods -----
+
+ function getTopPosition(block) {
+ const num = block.row * playingBoard.getBlockHeight();
+ return `${num}px`;
+ }
+
+ function getLeftPosition(block) {
+ const num = block.col * playingBoard.getBlockWidth();
+ return `${num}px`;
+ }
+
+ function createSnakeElement() {
+ const tempNode = document.createElement("div");
+ tempNode.className = "snake-snakebody-block";
+ tempNode.style.left = "-1000px";
+ tempNode.style.top = "-1000px";
+ tempNode.style.width = playingBoard.getBlockWidth() + "px";
+ tempNode.style.height = playingBoard.getBlockHeight() + "px";
+ return tempNode;
+ }
+
+ function createBlocks(num) {
+ let tempBlock;
+ const tempNode = createSnakeElement();
+
+ for (let ii = 1; ii < num; ii++) {
+ tempBlock = new SnakeBlock();
+ tempBlock.elm = tempNode.cloneNode(true);
+ tempBlock.elmStyle = tempBlock.elm.style;
+ playingBoard.getBoardContainer().appendChild(tempBlock.elm);
+ blockPool[blockPool.length] = tempBlock;
+ }
+
+ tempBlock = new SnakeBlock();
+ tempBlock.elm = tempNode;
+ playingBoard.getBoardContainer().appendChild(tempBlock.elm);
+ blockPool[blockPool.length] = tempBlock;
+ }
+
+ function recordScore() {
+ const highScore = localStorage[HIGH_SCORE_KEY];
+ if (me.snakeLength > highScore) {
+ alert(
+ "Congratulations! You have beaten your previous high score, which was " +
+ highScore +
+ ".",
+ );
+ localStorage.setItem(HIGH_SCORE_KEY, me.snakeLength);
+ }
+ }
+
+ function handleEndCondition(handleFunc) {
+ recordScore();
+ me.snakeHead.elm.style.zIndex = getNextHighestZIndex(me.snakeBody);
+ me.snakeHead.elm.className = me.snakeHead.elm.className.replace(
+ /\bsnake-snakebody-alive\b/,
+ "",
+ );
+ me.snakeHead.elm.className += " snake-snakebody-dead";
+
+ isDead = true;
+ handleFunc();
+ }
+
+ // ----- public methods -----
+
+ me.setPaused = function (val) {
+ isPaused = val;
+ };
+ me.getPaused = function () {
+ return isPaused;
+ };
+
+ /**
+ * This method sets the snake direction
+ * @param direction
+ */
+ me.setDirection = (direction) => {
+ if (currentDirection !== lastMove) {
+ // Allow a queue of 1 premove so you can turn again before the first turn registers
+ preMove = direction;
+ }
+ if (Math.abs(direction - lastMove) !== 2 || isFirstGameMove) {
+ // Prevent snake from turning 180 degrees
+ currentDirection = direction;
+ isFirstGameMove = false;
+ }
+ };
+
+ /**
+ * This method is called when a user presses a key. It logs arrow key presses in "currentDirection", which is used when the snake needs to make its next move.
+ * @method handleArrowKeys
+ * @param {Number} keyNum A number representing the key that was pressed.
+ */
+ /*
+ Handles what happens when an arrow key is pressed.
+ Direction explained (0 = up, etc etc)
+ 0
+ 3 1
+ 2
+ */
+ me.handleArrowKeys = function (keyNum) {
+ if (isDead || (isPaused && !config.premoveOnPause)) {
+ return;
+ }
+
+ let directionFound = MOVE_NONE;
+
+ switch (keyNum) {
+ case 37:
+ case 65:
+ directionFound = MOVE_LEFT;
+ break;
+ case 38:
+ case 87:
+ directionFound = MOVE_UP;
+ break;
+ case 39:
+ case 68:
+ directionFound = MOVE_RIGHT;
+ break;
+ case 40:
+ case 83:
+ directionFound = MOVE_DOWN;
+ break;
+ }
+ me.setDirection(directionFound);
+ };
+
+ /**
+ * This method is executed for each move of the snake. It determines where the snake will go and what will happen to it. This method needs to run quickly.
+ * @method go
+ */
+ me.go = function () {
+ const oldHead = me.snakeHead,
+ newHead = me.snakeTail,
+ grid = playingBoard.grid; // cache grid for quicker lookup
+
+ if (isPaused === true) {
+ setTimeout(function () {
+ me.go();
+ }, snakeSpeed);
+ return;
+ }
+
+ // code to execute if snake is being moved by AI
+ if (config.moveSnakeWithAI) {
+ config.moveSnakeWithAI({
+ grid,
+ snakeHead: me.snakeHead,
+ currentDirection,
+ isFirstGameMove,
+ setDirection: me.setDirection,
+ });
+ }
+
+ me.snakeTail = newHead.prev;
+ me.snakeHead = newHead;
+
+ // clear the old board position
+ if (grid[newHead.row] && grid[newHead.row][newHead.col]) {
+ grid[newHead.row][newHead.col] = 0;
+ }
+
+ if (currentDirection !== MOVE_NONE) {
+ lastMove = currentDirection;
+ if (preMove !== MOVE_NONE) {
+ // If the user queued up another move after the current one
+ currentDirection = preMove; // Execute that move next time (unless overwritten)
+ preMove = MOVE_NONE;
+ }
+ }
+
+ newHead.col = oldHead.col + columnShift[lastMove];
+ newHead.row = oldHead.row + rowShift[lastMove];
+
+ if (!newHead.elmStyle) {
+ newHead.elmStyle = newHead.elm.style;
+ }
+
+ newHead.elmStyle.left = getLeftPosition(newHead);
+ newHead.elmStyle.top = getTopPosition(newHead);
+ if (me.snakeLength > 1) {
+ newHead.elm.id = "snake-snakehead-alive";
+ oldHead.elm.id = "";
+ }
+
+ // check the new spot the snake moved into
+
+ if (grid[newHead.row][newHead.col] === 0) {
+ grid[newHead.row][newHead.col] = 1;
+ setTimeout(function () {
+ me.go();
+ }, snakeSpeed);
+ } else if (grid[newHead.row][newHead.col] > 0) {
+ me.handleDeath();
+ } else if (
+ grid[newHead.row][newHead.col] === playingBoard.getGridFoodValue()
+ ) {
+ grid[newHead.row][newHead.col] = 1;
+ if (!me.eatFood()) {
+ me.handleWin();
+ return;
+ }
+ setTimeout(function () {
+ me.go();
+ }, snakeSpeed);
+ }
+ };
+
+ /**
+ * This method is called when it is determined that the snake has eaten some food.
+ * @method eatFood
+ * @return {bool} Whether a new food was able to spawn (true)
+ * or not (false) after the snake eats food.
+ */
+ me.eatFood = function () {
+ if (blockPool.length <= growthIncr) {
+ createBlocks(growthIncr * 2);
+ }
+ const blocks = blockPool.splice(0, growthIncr);
+
+ let ii = blocks.length,
+ index;
+ prevNode = me.snakeTail;
+ while (ii--) {
+ index = "b" + me.snakeLength++;
+ me.snakeBody[index] = blocks[ii];
+ me.snakeBody[index].prev = prevNode;
+ me.snakeBody[index].elm.className =
+ me.snakeHead.elm.className.replace(/\bsnake-snakebody-dead\b/, "");
+ me.snakeBody[index].elm.className += " snake-snakebody-alive";
+ prevNode.next = me.snakeBody[index];
+ prevNode = me.snakeBody[index];
+ }
+ me.snakeTail = me.snakeBody[index];
+ me.snakeTail.next = me.snakeHead;
+ me.snakeHead.prev = me.snakeTail;
+
+ if (!playingBoard.foodEaten()) {
+ return false;
+ }
+
+ //Checks if the current selected option is that of "Rush"
+ //If so, "increase" the snake speed
+ const selectDropDown = document.getElementById("selectMode");
+ const selectedOption =
+ selectDropDown.options[selectDropDown.selectedIndex];
+
+ if (selectedOption.text.localeCompare("Rush") == 0) {
+ if (snakeSpeed > MIN_SNAKE_SPEED + RUSH_INCR) {
+ snakeSpeed -= RUSH_INCR;
+ }
+ }
+
+ return true;
+ };
+
+ /**
+ * This method handles what happens when the snake dies.
+ * @method handleDeath
+ */
+ me.handleDeath = function () {
+ //Reset speed
+ const selectedSpeed = document.getElementById("selectMode").value;
+ snakeSpeed = parseInt(selectedSpeed);
+
+ handleEndCondition(playingBoard.handleDeath);
+ };
+
+ /**
+ * This method handles what happens when the snake wins.
+ * @method handleDeath
+ */
+ me.handleWin = function () {
+ handleEndCondition(playingBoard.handleWin);
+ };
+
+ /**
+ * This method sets a flag that lets the snake be alive again.
+ * @method rebirth
+ */
+ me.rebirth = function () {
+ isDead = false;
+ isFirstGameMove = true;
+ preMove = MOVE_NONE;
+ };
+
+ /**
+ * This method reset the snake so it is ready for a new game.
+ * @method reset
+ */
+ me.reset = function () {
+ if (isDead === false) {
+ return;
+ }
+
+ const blocks = [];
+ let curNode = me.snakeHead.next;
+ let nextNode;
+
+ while (curNode !== me.snakeHead) {
+ nextNode = curNode.next;
+ curNode.prev = null;
+ curNode.next = null;
+ blocks.push(curNode);
+ curNode = nextNode;
+ }
+ me.snakeHead.next = me.snakeHead;
+ me.snakeHead.prev = me.snakeHead;
+ me.snakeTail = me.snakeHead;
+ me.snakeLength = 1;
+
+ for (let ii = 0; ii < blocks.length; ii++) {
+ blocks[ii].elm.style.left = "-1000px";
+ blocks[ii].elm.style.top = "-1000px";
+ blocks[ii].elm.className = me.snakeHead.elm.className.replace(
+ /\bsnake-snakebody-dead\b/,
+ "",
+ );
+ blocks[ii].elm.className += " snake-snakebody-alive";
+ }
+
+ blockPool.concat(blocks);
+ me.snakeHead.elm.className = me.snakeHead.elm.className.replace(
+ /\bsnake-snakebody-dead\b/,
+ "",
+ );
+ me.snakeHead.elm.className += " snake-snakebody-alive";
+ me.snakeHead.elm.id = "snake-snakehead-alive";
+ me.snakeHead.row = config.startRow || 1;
+ me.snakeHead.col = config.startCol || 1;
+ me.snakeHead.elm.style.left = getLeftPosition(me.snakeHead);
+ me.snakeHead.elm.style.top = getTopPosition(me.snakeHead);
+ };
+
+ me.getSpeed = () => {
+ return snakeSpeed;
+ };
+ me.setSpeed = (speed) => {
+ snakeSpeed = speed;
+ };
+
+ // ---------------------------------------------------------------------
+ // Initialize
+ // ---------------------------------------------------------------------
+ createBlocks(growthIncr * 2);
+ };
+ })();
+
+/**
+ * This class manages the food which the snake will eat.
+ * @class Food
+ * @constructor
+ * @namespace SNAKE
+ * @param {Object} config The configuration object for the class. Contains playingBoard (the SNAKE.Board that this food resides in).
+ */
+
+SNAKE.Food =
+ SNAKE.Food ||
+ (function () {
+ // -------------------------------------------------------------------------
+ // Private static variables and methods
+ // -------------------------------------------------------------------------
+
+ let instanceNumber = 0;
+
+ function getRandomPosition(x, y) {
+ return Math.floor(Math.random() * (y + 1 - x)) + x;
+ }
+
+ // -------------------------------------------------------------------------
+ // Contructor + public and private definitions
+ // -------------------------------------------------------------------------
+
+ /*
+ config options:
+ playingBoard - the SnakeBoard that this object belongs too.
+ */
+ return function (config) {
+ if (!config || !config.playingBoard) {
+ return;
+ }
+
+ // ----- private variables -----
+
+ const me = this;
+ const playingBoard = config.playingBoard;
+ let fRow, fColumn;
+ const myId = instanceNumber++;
+
+ const elmFood = document.createElement("div");
+ elmFood.setAttribute("id", "snake-food-" + myId);
+ elmFood.className = "snake-food-block";
+ elmFood.style.width = playingBoard.getBlockWidth() + "px";
+ elmFood.style.height = playingBoard.getBlockHeight() + "px";
+ elmFood.style.left = "-1000px";
+ elmFood.style.top = "-1000px";
+ playingBoard.getBoardContainer().appendChild(elmFood);
+
+ // ----- public methods -----
+
+ /**
+ * @method getFoodElement
+ * @return {DOM Element} The div the represents the food.
+ */
+ me.getFoodElement = function () {
+ return elmFood;
+ };
+
+ /**
+ * Randomly places the food onto an available location on the playing board.
+ * @method randomlyPlaceFood
+ * @return {bool} Whether a food was able to spawn (true) or not (false).
+ */
+ me.randomlyPlaceFood = function () {
+ // if there exist some food, clear its presence from the board
+ if (
+ playingBoard.grid[fRow] &&
+ playingBoard.grid[fRow][fColumn] === playingBoard.getGridFoodValue()
+ ) {
+ playingBoard.grid[fRow][fColumn] = 0;
+ }
+
+ let row = 0,
+ col = 0,
+ numTries = 0;
+
+ const maxRows = playingBoard.grid.length - 1;
+ const maxCols = playingBoard.grid[0].length - 1;
+
+ while (playingBoard.grid[row][col] !== 0) {
+ row = getRandomPosition(1, maxRows);
+ col = getRandomPosition(1, maxCols);
+
+ // in some cases there may not be any room to put food anywhere
+ // instead of freezing, exit out (and return false to indicate
+ // that the player beat the game)
+ numTries++;
+ if (numTries > 20000) {
+ return false;
+ }
+ }
+
+ playingBoard.grid[row][col] = playingBoard.getGridFoodValue();
+ fRow = row;
+ fColumn = col;
+ elmFood.style.top = row * playingBoard.getBlockHeight() + "px";
+ elmFood.style.left = col * playingBoard.getBlockWidth() + "px";
+ return true;
+ };
+ };
+ })();
+
+/**
+ * This class manages playing board for the game.
+ * @class Board
+ * @constructor
+ * @namespace SNAKE
+ * @param {Object} config The configuration object for the class. Set fullScreen equal to true if you want the game to take up the full screen, otherwise, set the top, left, width and height parameters.
+ */
+
+SNAKE.Board =
+ SNAKE.Board ||
+ (function () {
+ // -------------------------------------------------------------------------
+ // Private static variables and methods
+ // -------------------------------------------------------------------------
+
+ let instanceNumber = 0;
+
+ // this function is adapted from the example at http://greengeckodesign.com/blog/2007/07/get-highest-z-index-in-javascript.html
+ function getNextHighestZIndex(myObj) {
+ let highestIndex = 0,
+ currentIndex = 0,
+ ii;
+ for (ii in myObj) {
+ if (myObj[ii].elm.currentStyle) {
+ currentIndex = parseFloat(myObj[ii].elm.style["z-index"], 10);
+ } else if (window.getComputedStyle) {
+ currentIndex = parseFloat(
+ document.defaultView
+ .getComputedStyle(myObj[ii].elm, null)
+ .getPropertyValue("z-index"),
+ 10,
+ );
+ }
+ if (!isNaN(currentIndex) && currentIndex > highestIndex) {
+ highestIndex = currentIndex;
+ }
+ }
+ return highestIndex + 1;
+ }
+
+ /*
+ This function returns the width of the available screen real estate that we have
+ */
+ function getClientWidth() {
+ let myWidth = 0;
+ if (typeof window.innerWidth === "number") {
+ myWidth = window.innerWidth; //Non-IE
+ } else if (
+ document.documentElement &&
+ (document.documentElement.clientWidth ||
+ document.documentElement.clientHeight)
+ ) {
+ myWidth = document.documentElement.clientWidth; //IE 6+ in 'standards compliant mode'
+ } else if (
+ document.body &&
+ (document.body.clientWidth || document.body.clientHeight)
+ ) {
+ myWidth = document.body.clientWidth; //IE 4 compatible
+ }
+ return myWidth;
+ }
+
+ /*
+ This function returns the height of the available screen real estate that we have
+ */
+ function getClientHeight() {
+ let myHeight = 0;
+ if (typeof window.innerHeight === "number") {
+ myHeight = window.innerHeight; //Non-IE
+ } else if (
+ document.documentElement &&
+ (document.documentElement.clientWidth ||
+ document.documentElement.clientHeight)
+ ) {
+ myHeight = document.documentElement.clientHeight; //IE 6+ in 'standards compliant mode'
+ } else if (
+ document.body &&
+ (document.body.clientWidth || document.body.clientHeight)
+ ) {
+ myHeight = document.body.clientHeight; //IE 4 compatible
+ }
+ return myHeight;
+ }
+
+ // -------------------------------------------------------------------------
+ // Contructor + public and private definitions
+ // -------------------------------------------------------------------------
+
+ return function (inputConfig) {
+ // --- private variables ---
+ const me = this;
+ const myId = instanceNumber++;
+ const config = inputConfig || {};
+ const MAX_BOARD_COLS = 250;
+ const MAX_BOARD_ROWS = 250;
+ const blockWidth = 20;
+ const blockHeight = 20;
+ const GRID_FOOD_VALUE = -1; // the value of a spot on the board that represents snake food; MUST BE NEGATIVE
+
+ // defaults
+ if (!config.onLengthUpdate) {
+ config.onLengthUpdate = () => {};
+ }
+
+ if (!config.onPauseToggle) {
+ config.onPauseToggle = () => {};
+ }
+ if (!config.onWin) {
+ config.onWin = () => {};
+ }
+ if (!config.onDeath) {
+ config.onDeath = () => {};
+ }
+
+ let myFood,
+ mySnake,
+ boardState = BOARD_READY, // 0: in active, 1: awaiting game start, 2: playing game
+ myKeyListener,
+ myWindowListener,
+ isPaused = false; //note: both the board and the snake can be paused
+
+ // Board components
+ let elmContainer,
+ elmPlayingField,
+ elmAboutPanel,
+ elmLengthPanel,
+ elmHighscorePanel,
+ elmWelcome,
+ elmTryAgain,
+ elmWin,
+ elmPauseScreen;
+
+ // --- public variables ---
+ me.grid = [];
+
+ // ---------------------------------------------------------------------
+ // private functions
+ // ---------------------------------------------------------------------
+
+ function getStartRow() {
+ return config.startRow || 2;
+ }
+
+ function getStartCol() {
+ return config.startCol || 2;
+ }
+
+ function createBoardElements() {
+ elmPlayingField = document.createElement("div");
+ elmPlayingField.setAttribute("id", "playingField");
+ elmPlayingField.className = "snake-playing-field";
+
+ SNAKE.addEventListener(
+ elmPlayingField,
+ "click",
+ function () {
+ elmContainer.focus();
+ },
+ false,
+ );
+
+ elmPauseScreen = document.createElement("div");
+ elmPauseScreen.className = "snake-pause-screen";
+ elmPauseScreen.innerHTML =
+ "[Paused]
Press [space] to unpause.
";
+
+ elmAboutPanel = document.createElement("div");
+ elmAboutPanel.className = "snake-panel-component";
+ elmAboutPanel.innerHTML =
+ "more patorjk.com apps - source code - pat's youtube";
+
+ elmLengthPanel = document.createElement("div");
+ elmLengthPanel.className = "snake-panel-component";
+ elmLengthPanel.innerHTML = "Length: 1";
+
+ elmHighscorePanel = document.createElement("div");
+ elmHighscorePanel.className = "snake-panel-component";
+ elmHighscorePanel.innerHTML =
+ "Highscore: " + (localStorage[HIGH_SCORE_KEY] || 0);
+
+ // if it's not AI, show the dialogs
+ if (!config.moveSnakeWithAI) {
+ elmWelcome = createWelcomeElement();
+ elmTryAgain = createTryAgainElement();
+ elmWin = createWinElement();
+ }
+
+ SNAKE.addEventListener(
+ elmContainer,
+ "keyup",
+ function (evt) {
+ if (!evt) evt = window.event;
+ evt.cancelBubble = true;
+ if (evt.stopPropagation) {
+ evt.stopPropagation();
+ }
+ if (evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+ },
+ false,
+ );
+
+ elmContainer.className = "snake-game-container";
+
+ elmPauseScreen.style.zIndex = 10000;
+ elmContainer.appendChild(elmPauseScreen);
+ elmContainer.appendChild(elmPlayingField);
+ elmContainer.appendChild(elmAboutPanel);
+ elmContainer.appendChild(elmLengthPanel);
+ elmContainer.appendChild(elmHighscorePanel);
+
+ // nothing to attach if using AI
+ if (!config.moveSnakeWithAI) {
+ elmContainer.appendChild(elmWelcome);
+ elmContainer.appendChild(elmTryAgain);
+ elmContainer.appendChild(elmWin);
+ }
+
+ mySnake = new SNAKE.Snake({
+ playingBoard: me,
+ startRow: getStartRow(),
+ startCol: getStartCol(),
+ premoveOnPause: config.premoveOnPause,
+ moveSnakeWithAI: config.moveSnakeWithAI,
+ });
+ myFood = new SNAKE.Food({ playingBoard: me });
+
+ if (elmWelcome) {
+ elmWelcome.style.zIndex = 1000;
+ }
+ }
+
+ function maxBoardWidth() {
+ return MAX_BOARD_COLS * me.getBlockWidth();
+ }
+
+ function maxBoardHeight() {
+ return MAX_BOARD_ROWS * me.getBlockHeight();
+ }
+
+ function createWelcomeElement() {
+ const tmpElm = document.createElement("div");
+ tmpElm.id = "sbWelcome" + myId;
+ tmpElm.className = "snake-welcome-dialog";
+
+ const welcomeTxt = document.createElement("div");
+ let fullScreenText = "";
+ if (config.fullScreen) {
+ fullScreenText = "On Windows, press F11 to play in Full Screen mode.";
+ }
+ welcomeTxt.innerHTML =
+ "JavaScript SnakeUse the arrow keys on your keyboard to play the game. " +
+ fullScreenText +
+ "";
+ const welcomeStart = document.createElement("button");
+ welcomeStart.appendChild(document.createTextNode("Play Game"));
+
+ const loadGame = function () {
+ SNAKE.removeEventListener(window, "keyup", kbShortcut, false);
+ tmpElm.style.display = "none";
+ me.setBoardState(BOARD_READY);
+ me.getBoardContainer().focus();
+ };
+
+ const kbShortcut = function (evt) {
+ if (!evt) evt = window.event;
+ const keyNum = evt.which ? evt.which : evt.keyCode;
+ if (keyNum === 32 || keyNum === 13) {
+ loadGame();
+ }
+ };
+
+ SNAKE.addEventListener(window, "keyup", kbShortcut, false);
+ SNAKE.addEventListener(welcomeStart, "click", loadGame, false);
+
+ tmpElm.appendChild(welcomeTxt);
+ tmpElm.appendChild(welcomeStart);
+ return tmpElm;
+ }
+
+ function createGameEndElement(message, elmId, elmClassName) {
+ const tmpElm = document.createElement("div");
+ tmpElm.id = elmId + myId;
+ tmpElm.className = elmClassName;
+
+ const gameEndTxt = document.createElement("div");
+ gameEndTxt.innerHTML = "JavaScript Snake" + message + "";
+ const gameEndStart = document.createElement("button");
+ gameEndStart.appendChild(document.createTextNode("Play Again?"));
+
+ const reloadGame = function () {
+ tmpElm.style.display = "none";
+ me.resetBoard();
+ me.setBoardState(BOARD_READY);
+ me.getBoardContainer().focus();
+ };
+
+ const kbGameEndShortcut = function (evt) {
+ if (boardState !== 0 || tmpElm.style.display !== "block") {
+ return;
+ }
+ if (!evt) evt = window.event;
+ const keyNum = evt.which ? evt.which : evt.keyCode;
+ if (keyNum === 32 || keyNum === 13) {
+ reloadGame();
+ }
+ };
+ SNAKE.addEventListener(window, "keyup", kbGameEndShortcut, true);
+
+ SNAKE.addEventListener(gameEndStart, "click", reloadGame, false);
+ tmpElm.appendChild(gameEndTxt);
+ tmpElm.appendChild(gameEndStart);
+ return tmpElm;
+ }
+
+ function createTryAgainElement() {
+ return createGameEndElement(
+ "You died :(",
+ "sbTryAgain",
+ "snake-try-again-dialog",
+ );
+ }
+
+ function createWinElement() {
+ return createGameEndElement("You win! :D", "sbWin", "snake-win-dialog");
+ }
+
+ function handleEndCondition(elmDialog) {
+ const index = Math.max(
+ getNextHighestZIndex(mySnake.snakeBody),
+ getNextHighestZIndex({ tmp: { elm: myFood.getFoodElement() } }),
+ );
+ if (elmDialog) {
+ elmContainer.removeChild(elmDialog);
+ elmContainer.appendChild(elmDialog);
+ elmDialog.style.zIndex = index;
+ elmDialog.style.display = "block";
+ }
+ me.setBoardState(BOARD_NOT_READY);
+ }
+
+ // ---------------------------------------------------------------------
+ // public functions
+ // ---------------------------------------------------------------------
+
+ me.setPaused = function (val) {
+ isPaused = val;
+ mySnake.setPaused(val);
+ if (isPaused) {
+ elmPauseScreen.style.display = "block";
+ } else {
+ elmPauseScreen.style.display = "none";
+ }
+ config.onPauseToggle(isPaused);
+ };
+ me.getPaused = function () {
+ return isPaused;
+ };
+
+ /**
+ * Resets the playing board for a new game.
+ * @method resetBoard
+ */
+ me.resetBoard = function () {
+ SNAKE.removeEventListener(
+ elmContainer,
+ "keydown",
+ myKeyListener,
+ false,
+ );
+ SNAKE.removeEventListener(
+ elmContainer,
+ "visibilitychange",
+ myWindowListener,
+ false,
+ );
+ mySnake.reset();
+ config.onLengthUpdate(1);
+ elmLengthPanel.innerHTML = "Length: 1";
+ me.setupPlayingField();
+ me.grid[getStartRow()][getStartCol()] = 1; // snake head
+ };
+ /**
+ * Gets the current state of the playing board. There are 3 states: 0 - Welcome or Try Again dialog is present. 1 - User has pressed "Start Game" on the Welcome or Try Again dialog but has not pressed an arrow key to move the snake. 2 - The game is in progress and the snake is moving.
+ * @method getBoardState
+ * @return {Number} The state of the board.
+ */
+ me.getBoardState = function () {
+ return boardState;
+ };
+ /**
+ * Sets the current state of the playing board. There are 3 states: 0 - Welcome or Try Again dialog is present. 1 - User has pressed "Start Game" on the Welcome or Try Again dialog but has not pressed an arrow key to move the snake. 2 - The game is in progress and the snake is moving.
+ * @method setBoardState
+ * @param {Number} state The state of the board.
+ */
+ me.setBoardState = function (state) {
+ boardState = state;
+ };
+ /**
+ * @method getGridFoodValue
+ * @return {Number} A number that represents food on a number representation of the playing board.
+ */
+ me.getGridFoodValue = function () {
+ return GRID_FOOD_VALUE;
+ };
+ /**
+ * @method getPlayingFieldElement
+ * @return {DOM Element} The div representing the playing field (this is where the snake can move).
+ */
+ me.getPlayingFieldElement = function () {
+ return elmPlayingField;
+ };
+ /**
+ * @method setBoardContainer
+ * @param {DOM Element or String} myContainer Sets the container element for the game.
+ */
+ me.setBoardContainer = function (myContainer) {
+ if (typeof myContainer === "string") {
+ myContainer = document.getElementById(myContainer);
+ }
+ if (myContainer === elmContainer) {
+ return;
+ }
+ elmContainer = myContainer;
+ elmPlayingField = null;
+ me.setupPlayingField();
+ me.grid[getStartRow()][getStartCol()] = 1; // snake head
+ };
+ /**
+ * @method getBoardContainer
+ * @return {DOM Element}
+ */
+ me.getBoardContainer = function () {
+ return elmContainer;
+ };
+ /**
+ * @method getBlockWidth
+ * @return {Number}
+ */
+ me.getBlockWidth = function () {
+ return blockWidth;
+ };
+ /**
+ * @method getBlockHeight
+ * @return {Number}
+ */
+ me.getBlockHeight = function () {
+ return blockHeight;
+ };
+ /**
+ * Sets up the playing field.
+ * @method setupPlayingField
+ */
+ me.setupPlayingField = function () {
+ if (!elmPlayingField) {
+ createBoardElements();
+ } // create playing field
+
+ // calculate width of our game container
+ let cWidth, cHeight;
+ let cTop, cLeft;
+ if (config.fullScreen === true) {
+ cTop = 0;
+ cLeft = 0;
+ cWidth = getClientWidth() - 20;
+ cHeight = getClientHeight() - 20;
+ } else {
+ cTop = config.top;
+ cLeft = config.left;
+ cWidth = config.width;
+ cHeight = config.height;
+ }
+
+ // define the dimensions of the board and playing field
+ const wEdgeSpace =
+ me.getBlockWidth() * 2 + (cWidth % me.getBlockWidth());
+ const fWidth = Math.min(
+ maxBoardWidth() - wEdgeSpace,
+ cWidth - wEdgeSpace,
+ );
+ const hEdgeSpace =
+ me.getBlockHeight() * 3 + (cHeight % me.getBlockHeight());
+ const fHeight = Math.min(
+ maxBoardHeight() - hEdgeSpace,
+ cHeight - hEdgeSpace,
+ );
+
+ elmContainer.style.left = cLeft + "px";
+ elmContainer.style.top = cTop + "px";
+ elmContainer.style.width = cWidth + "px";
+ elmContainer.style.height = cHeight + "px";
+ elmPlayingField.style.left = me.getBlockWidth() + "px";
+ elmPlayingField.style.top = me.getBlockHeight() + "px";
+ elmPlayingField.style.width = fWidth + "px";
+ elmPlayingField.style.height = fHeight + "px";
+
+ // the math for this will need to change depending on font size, padding, etc
+ // assuming height of 14 (font size) + 8 (padding)
+ const bottomPanelHeight = hEdgeSpace - me.getBlockHeight();
+ const pLabelTop =
+ me.getBlockHeight() +
+ fHeight +
+ Math.round((bottomPanelHeight - 30) / 2) +
+ "px";
+
+ elmAboutPanel.style.top = pLabelTop;
+ elmAboutPanel.style.width = "450px";
+ elmAboutPanel.style.left =
+ Math.round(cWidth / 2) - Math.round(450 / 2) + "px";
+
+ elmLengthPanel.style.top = pLabelTop;
+ elmLengthPanel.style.left = 30 + "px";
+
+ elmHighscorePanel.style.top = pLabelTop;
+ elmHighscorePanel.style.left = cWidth - 140 + "px";
+
+ // if width is too narrow, hide the about panel
+ if (cWidth < 700) {
+ elmAboutPanel.style.display = "none";
+ } else {
+ elmAboutPanel.style.display = "block";
+ }
+
+ me.grid = [];
+ const numBoardCols = fWidth / me.getBlockWidth() + 2;
+ const numBoardRows = fHeight / me.getBlockHeight() + 2;
+
+ for (let row = 0; row < numBoardRows; row++) {
+ me.grid[row] = [];
+ for (let col = 0; col < numBoardCols; col++) {
+ if (
+ col === 0 ||
+ row === 0 ||
+ col === numBoardCols - 1 ||
+ row === numBoardRows - 1
+ ) {
+ me.grid[row][col] = 1; // an edge
+ } else {
+ me.grid[row][col] = 0; // empty space
+ }
+ }
+ }
+
+ myFood.randomlyPlaceFood();
+ config.onLengthUpdate(1);
+
+ myKeyListener = function (evt) {
+ if (!evt) evt = window.event;
+ const keyNum = evt.which ? evt.which : evt.keyCode;
+
+ if (me.getBoardState() === BOARD_READY) {
+ if (
+ !(keyNum >= 37 && keyNum <= 40) &&
+ !(
+ keyNum === 87 ||
+ keyNum === 65 ||
+ keyNum === 83 ||
+ keyNum === 68
+ )
+ ) {
+ return;
+ } // if not an arrow key, leave
+
+ // This removes the listener added at the #listenerX line
+ SNAKE.removeEventListener(
+ elmContainer,
+ "keydown",
+ myKeyListener,
+ false,
+ );
+ SNAKE.removeEventListener(
+ elmContainer,
+ "visibilitychange",
+ myWindowListener,
+ false,
+ );
+
+ myKeyListener = function (evt) {
+ if (!evt) evt = window.event;
+ const keyNum = evt.which ? evt.which : evt.keyCode;
+
+ if (keyNum === 32) {
+ if (me.getBoardState() != BOARD_NOT_READY)
+ me.setPaused(!me.getPaused());
+ }
+
+ mySnake.handleArrowKeys(keyNum);
+
+ evt.cancelBubble = true;
+ if (evt.stopPropagation) {
+ evt.stopPropagation();
+ }
+ if (evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+ };
+
+ //listener for pausing the game if user change tab or minimize the browser window
+ document.addEventListener("visibilitychange", () => {
+ if (document.visibilityState === "hidden") {
+ if (me.getBoardState() != BOARD_NOT_READY && !me.getPaused())
+ me.setPaused(true);
+ }
+ });
+
+ SNAKE.addEventListener(
+ elmContainer,
+ "keydown",
+ myKeyListener,
+ false,
+ );
+ SNAKE.addEventListener(
+ elmContainer,
+ "visibilitychange",
+ myWindowListener,
+ false,
+ );
+
+ mySnake.rebirth();
+ mySnake.handleArrowKeys(keyNum);
+ me.setBoardState(BOARD_IN_PLAY); // start the game!
+ mySnake.go();
+ }
+
+ evt.cancelBubble = true;
+ if (evt.stopPropagation) {
+ evt.stopPropagation();
+ }
+ if (evt.preventDefault) {
+ evt.preventDefault();
+ }
+ return false;
+ };
+
+ // Search for #listenerX to see where this is removed
+ if (!config.moveSnakeWithAI) {
+ SNAKE.addEventListener(elmContainer, "keydown", myKeyListener, false);
+ SNAKE.addEventListener(
+ elmContainer,
+ "visibilitychange",
+ myWindowListener,
+ false,
+ );
+ }
+ };
+
+ /**
+ * This method is called when the snake has eaten some food.
+ * @method foodEaten
+ * @return {bool} Whether a new food was able to spawn (true)
+ * or not (false) after the snake eats food.
+ */
+ me.foodEaten = function () {
+ config.onLengthUpdate(mySnake.snakeLength);
+ elmLengthPanel.innerHTML = "Length: " + mySnake.snakeLength;
+ if (mySnake.snakeLength > localStorage[HIGH_SCORE_KEY]) {
+ localStorage.setItem(HIGH_SCORE_KEY, mySnake.snakeLength);
+ elmHighscorePanel.innerHTML =
+ "Highscore: " + localStorage[HIGH_SCORE_KEY];
+ }
+ if (!myFood.randomlyPlaceFood()) {
+ return false;
+ }
+ return true;
+ };
+
+ /**
+ * This method is called when the snake dies.
+ * @method handleDeath
+ */
+ me.handleDeath = function () {
+ handleEndCondition(elmTryAgain);
+ config.onDeath({ startAIGame: me.startAIGame });
+ };
+
+ /**
+ * This method is called when the snake wins.
+ * @method handleWin
+ */
+ me.handleWin = function () {
+ handleEndCondition(elmWin);
+ config.onWin({ startAIGame: me.startAIGame });
+ };
+
+ me.setSpeed = (speed) => {
+ mySnake.setSpeed(speed);
+ };
+ me.getSpeed = () => {
+ return mySnake.getSpeed();
+ };
+
+ me.startAIGame = () => {
+ me.resetBoard();
+ mySnake.rebirth();
+ me.setBoardState(BOARD_IN_PLAY); // start the game!
+ mySnake.go();
+ };
+
+ // ---------------------------------------------------------------------
+ // Initialize
+ // ---------------------------------------------------------------------
+
+ config.fullScreen =
+ typeof config.fullScreen === "undefined" ? false : config.fullScreen;
+ config.top = typeof config.top === "undefined" ? 0 : config.top;
+ config.left = typeof config.left === "undefined" ? 0 : config.left;
+ config.width = typeof config.width === "undefined" ? 400 : config.width;
+ config.height =
+ typeof config.height === "undefined" ? 400 : config.height;
+ config.premoveOnPause =
+ typeof config.premoveOnPause === "undefined"
+ ? false
+ : config.premoveOnPause;
+
+ if (config.fullScreen) {
+ SNAKE.addEventListener(
+ window,
+ "resize",
+ function () {
+ me.setupPlayingField();
+ },
+ false,
+ );
+ }
+
+ me.setBoardState(BOARD_NOT_READY);
+
+ if (config.boardContainer) {
+ me.setBoardContainer(config.boardContainer);
+ }
+
+ const reloadGame = function () {
+ me.resetBoard();
+ me.setBoardState(BOARD_READY);
+ me.getBoardContainer().focus();
+ };
+
+ if (config.onInit) {
+ config.onInit({
+ reloadGame,
+ getSpeed: me.getSpeed,
+ setSpeed: me.setSpeed,
+ startAIGame: me.startAIGame,
+ });
+ }
+ }; // end return function
+ })();