├── .gitignore ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public ├── favicon │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ └── site.webmanifest └── images │ └── site-screenshot.png ├── src ├── App.css ├── App.tsx ├── algorithms │ ├── AStar.ts │ ├── BFS.ts │ ├── DFS.ts │ ├── Dijkstra.ts │ ├── tsconfig.json │ └── types.ts ├── components │ ├── Node.css │ └── Node.tsx ├── data-structures │ ├── Node.ts │ └── tsconfig.json ├── index.css ├── main.tsx ├── utils │ └── dimension.ts └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

Algorithms Visualizer

6 |

7 | Visualization of common pathfinding algorithms 🧭 🗺️ 8 |

9 | 10 |

11 | Website 🔗 12 |

13 | 14 | ## Features 15 | 16 | - 🗺️ Visualize common pathfinding algorithms: DFS, BFS, Dijkstra, A*. 17 | - 🧭 Move start/end nodes freely to see optimal path changes. 18 | - 🧱 Allow walls creation. 19 | - 📞 Work on mobile, however some features are available on desktop only. 20 | 21 | ## Screenshots 22 | 23 |

Depth-first Search

24 |

25 | Visualization of Depth-first Search algorithm 28 |

29 | 30 |

Dijkstra's Algorithm

31 |

32 | Visualization of Dijkstra's algorithm 35 |

36 | 37 |

A* Algorithm

38 |

39 | Visualization of A-Star algorithm 42 |

43 | 44 | ## Clone this repo 45 | 46 | ```bash 47 | git clone git@github.com:sonngdev/algorithms-visualizer.git 48 | cd algorithms-visualizer 49 | npm install 50 | npm run dev 51 | ``` 52 | 53 | ## Author 54 | [Son Nguyen](https://github.com/sonngdev). 55 | Check out my [website](https://www.sonng.dev/). 56 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Algorithms Visualizer 30 | 31 | 32 |

33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-vite", 3 | "version": "0.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "react-vite", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "@fortawesome/fontawesome-svg-core": "^6.2.1", 12 | "@fortawesome/free-brands-svg-icons": "^6.2.1", 13 | "@fortawesome/free-solid-svg-icons": "^6.2.1", 14 | "@fortawesome/react-fontawesome": "^0.2.0", 15 | "immer": "^9.0.16", 16 | "react": "^18.0.0", 17 | "react-device-detect": "^2.2.3", 18 | "react-dom": "^18.0.0" 19 | }, 20 | "devDependencies": { 21 | "@types/react": "^18.0.0", 22 | "@types/react-dom": "^18.0.0", 23 | "@vitejs/plugin-react": "^1.3.0", 24 | "typescript": "^4.6.3", 25 | "vite": "^2.9.9" 26 | } 27 | }, 28 | "node_modules/@ampproject/remapping": { 29 | "version": "2.2.0", 30 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", 31 | "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", 32 | "dev": true, 33 | "dependencies": { 34 | "@jridgewell/gen-mapping": "^0.1.0", 35 | "@jridgewell/trace-mapping": "^0.3.9" 36 | }, 37 | "engines": { 38 | "node": ">=6.0.0" 39 | } 40 | }, 41 | "node_modules/@babel/code-frame": { 42 | "version": "7.18.6", 43 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", 44 | "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", 45 | "dev": true, 46 | "dependencies": { 47 | "@babel/highlight": "^7.18.6" 48 | }, 49 | "engines": { 50 | "node": ">=6.9.0" 51 | } 52 | }, 53 | "node_modules/@babel/compat-data": { 54 | "version": "7.18.8", 55 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", 56 | "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", 57 | "dev": true, 58 | "engines": { 59 | "node": ">=6.9.0" 60 | } 61 | }, 62 | "node_modules/@babel/core": { 63 | "version": "7.18.6", 64 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", 65 | "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", 66 | "dev": true, 67 | "dependencies": { 68 | "@ampproject/remapping": "^2.1.0", 69 | "@babel/code-frame": "^7.18.6", 70 | "@babel/generator": "^7.18.6", 71 | "@babel/helper-compilation-targets": "^7.18.6", 72 | "@babel/helper-module-transforms": "^7.18.6", 73 | "@babel/helpers": "^7.18.6", 74 | "@babel/parser": "^7.18.6", 75 | "@babel/template": "^7.18.6", 76 | "@babel/traverse": "^7.18.6", 77 | "@babel/types": "^7.18.6", 78 | "convert-source-map": "^1.7.0", 79 | "debug": "^4.1.0", 80 | "gensync": "^1.0.0-beta.2", 81 | "json5": "^2.2.1", 82 | "semver": "^6.3.0" 83 | }, 84 | "engines": { 85 | "node": ">=6.9.0" 86 | }, 87 | "funding": { 88 | "type": "opencollective", 89 | "url": "https://opencollective.com/babel" 90 | } 91 | }, 92 | "node_modules/@babel/generator": { 93 | "version": "7.18.7", 94 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", 95 | "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", 96 | "dev": true, 97 | "dependencies": { 98 | "@babel/types": "^7.18.7", 99 | "@jridgewell/gen-mapping": "^0.3.2", 100 | "jsesc": "^2.5.1" 101 | }, 102 | "engines": { 103 | "node": ">=6.9.0" 104 | } 105 | }, 106 | "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { 107 | "version": "0.3.2", 108 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", 109 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", 110 | "dev": true, 111 | "dependencies": { 112 | "@jridgewell/set-array": "^1.0.1", 113 | "@jridgewell/sourcemap-codec": "^1.4.10", 114 | "@jridgewell/trace-mapping": "^0.3.9" 115 | }, 116 | "engines": { 117 | "node": ">=6.0.0" 118 | } 119 | }, 120 | "node_modules/@babel/helper-annotate-as-pure": { 121 | "version": "7.18.6", 122 | "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", 123 | "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", 124 | "dev": true, 125 | "dependencies": { 126 | "@babel/types": "^7.18.6" 127 | }, 128 | "engines": { 129 | "node": ">=6.9.0" 130 | } 131 | }, 132 | "node_modules/@babel/helper-compilation-targets": { 133 | "version": "7.18.6", 134 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", 135 | "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", 136 | "dev": true, 137 | "dependencies": { 138 | "@babel/compat-data": "^7.18.6", 139 | "@babel/helper-validator-option": "^7.18.6", 140 | "browserslist": "^4.20.2", 141 | "semver": "^6.3.0" 142 | }, 143 | "engines": { 144 | "node": ">=6.9.0" 145 | }, 146 | "peerDependencies": { 147 | "@babel/core": "^7.0.0" 148 | } 149 | }, 150 | "node_modules/@babel/helper-environment-visitor": { 151 | "version": "7.18.6", 152 | "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", 153 | "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==", 154 | "dev": true, 155 | "engines": { 156 | "node": ">=6.9.0" 157 | } 158 | }, 159 | "node_modules/@babel/helper-function-name": { 160 | "version": "7.18.6", 161 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", 162 | "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", 163 | "dev": true, 164 | "dependencies": { 165 | "@babel/template": "^7.18.6", 166 | "@babel/types": "^7.18.6" 167 | }, 168 | "engines": { 169 | "node": ">=6.9.0" 170 | } 171 | }, 172 | "node_modules/@babel/helper-hoist-variables": { 173 | "version": "7.18.6", 174 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", 175 | "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", 176 | "dev": true, 177 | "dependencies": { 178 | "@babel/types": "^7.18.6" 179 | }, 180 | "engines": { 181 | "node": ">=6.9.0" 182 | } 183 | }, 184 | "node_modules/@babel/helper-module-imports": { 185 | "version": "7.18.6", 186 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", 187 | "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", 188 | "dev": true, 189 | "dependencies": { 190 | "@babel/types": "^7.18.6" 191 | }, 192 | "engines": { 193 | "node": ">=6.9.0" 194 | } 195 | }, 196 | "node_modules/@babel/helper-module-transforms": { 197 | "version": "7.18.8", 198 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.8.tgz", 199 | "integrity": "sha512-che3jvZwIcZxrwh63VfnFTUzcAM9v/lznYkkRxIBGMPt1SudOKHAEec0SIRCfiuIzTcF7VGj/CaTT6gY4eWxvA==", 200 | "dev": true, 201 | "dependencies": { 202 | "@babel/helper-environment-visitor": "^7.18.6", 203 | "@babel/helper-module-imports": "^7.18.6", 204 | "@babel/helper-simple-access": "^7.18.6", 205 | "@babel/helper-split-export-declaration": "^7.18.6", 206 | "@babel/helper-validator-identifier": "^7.18.6", 207 | "@babel/template": "^7.18.6", 208 | "@babel/traverse": "^7.18.8", 209 | "@babel/types": "^7.18.8" 210 | }, 211 | "engines": { 212 | "node": ">=6.9.0" 213 | } 214 | }, 215 | "node_modules/@babel/helper-plugin-utils": { 216 | "version": "7.18.6", 217 | "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", 218 | "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", 219 | "dev": true, 220 | "engines": { 221 | "node": ">=6.9.0" 222 | } 223 | }, 224 | "node_modules/@babel/helper-simple-access": { 225 | "version": "7.18.6", 226 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", 227 | "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", 228 | "dev": true, 229 | "dependencies": { 230 | "@babel/types": "^7.18.6" 231 | }, 232 | "engines": { 233 | "node": ">=6.9.0" 234 | } 235 | }, 236 | "node_modules/@babel/helper-split-export-declaration": { 237 | "version": "7.18.6", 238 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", 239 | "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", 240 | "dev": true, 241 | "dependencies": { 242 | "@babel/types": "^7.18.6" 243 | }, 244 | "engines": { 245 | "node": ">=6.9.0" 246 | } 247 | }, 248 | "node_modules/@babel/helper-validator-identifier": { 249 | "version": "7.18.6", 250 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", 251 | "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", 252 | "dev": true, 253 | "engines": { 254 | "node": ">=6.9.0" 255 | } 256 | }, 257 | "node_modules/@babel/helper-validator-option": { 258 | "version": "7.18.6", 259 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", 260 | "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", 261 | "dev": true, 262 | "engines": { 263 | "node": ">=6.9.0" 264 | } 265 | }, 266 | "node_modules/@babel/helpers": { 267 | "version": "7.18.6", 268 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz", 269 | "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==", 270 | "dev": true, 271 | "dependencies": { 272 | "@babel/template": "^7.18.6", 273 | "@babel/traverse": "^7.18.6", 274 | "@babel/types": "^7.18.6" 275 | }, 276 | "engines": { 277 | "node": ">=6.9.0" 278 | } 279 | }, 280 | "node_modules/@babel/highlight": { 281 | "version": "7.18.6", 282 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", 283 | "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", 284 | "dev": true, 285 | "dependencies": { 286 | "@babel/helper-validator-identifier": "^7.18.6", 287 | "chalk": "^2.0.0", 288 | "js-tokens": "^4.0.0" 289 | }, 290 | "engines": { 291 | "node": ">=6.9.0" 292 | } 293 | }, 294 | "node_modules/@babel/parser": { 295 | "version": "7.18.8", 296 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.8.tgz", 297 | "integrity": "sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA==", 298 | "dev": true, 299 | "bin": { 300 | "parser": "bin/babel-parser.js" 301 | }, 302 | "engines": { 303 | "node": ">=6.0.0" 304 | } 305 | }, 306 | "node_modules/@babel/plugin-syntax-jsx": { 307 | "version": "7.18.6", 308 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", 309 | "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", 310 | "dev": true, 311 | "dependencies": { 312 | "@babel/helper-plugin-utils": "^7.18.6" 313 | }, 314 | "engines": { 315 | "node": ">=6.9.0" 316 | }, 317 | "peerDependencies": { 318 | "@babel/core": "^7.0.0-0" 319 | } 320 | }, 321 | "node_modules/@babel/plugin-transform-react-jsx": { 322 | "version": "7.18.6", 323 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz", 324 | "integrity": "sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==", 325 | "dev": true, 326 | "dependencies": { 327 | "@babel/helper-annotate-as-pure": "^7.18.6", 328 | "@babel/helper-module-imports": "^7.18.6", 329 | "@babel/helper-plugin-utils": "^7.18.6", 330 | "@babel/plugin-syntax-jsx": "^7.18.6", 331 | "@babel/types": "^7.18.6" 332 | }, 333 | "engines": { 334 | "node": ">=6.9.0" 335 | }, 336 | "peerDependencies": { 337 | "@babel/core": "^7.0.0-0" 338 | } 339 | }, 340 | "node_modules/@babel/plugin-transform-react-jsx-development": { 341 | "version": "7.18.6", 342 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", 343 | "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", 344 | "dev": true, 345 | "dependencies": { 346 | "@babel/plugin-transform-react-jsx": "^7.18.6" 347 | }, 348 | "engines": { 349 | "node": ">=6.9.0" 350 | }, 351 | "peerDependencies": { 352 | "@babel/core": "^7.0.0-0" 353 | } 354 | }, 355 | "node_modules/@babel/plugin-transform-react-jsx-self": { 356 | "version": "7.18.6", 357 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz", 358 | "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==", 359 | "dev": true, 360 | "dependencies": { 361 | "@babel/helper-plugin-utils": "^7.18.6" 362 | }, 363 | "engines": { 364 | "node": ">=6.9.0" 365 | }, 366 | "peerDependencies": { 367 | "@babel/core": "^7.0.0-0" 368 | } 369 | }, 370 | "node_modules/@babel/plugin-transform-react-jsx-source": { 371 | "version": "7.18.6", 372 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz", 373 | "integrity": "sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==", 374 | "dev": true, 375 | "dependencies": { 376 | "@babel/helper-plugin-utils": "^7.18.6" 377 | }, 378 | "engines": { 379 | "node": ">=6.9.0" 380 | }, 381 | "peerDependencies": { 382 | "@babel/core": "^7.0.0-0" 383 | } 384 | }, 385 | "node_modules/@babel/template": { 386 | "version": "7.18.6", 387 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", 388 | "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", 389 | "dev": true, 390 | "dependencies": { 391 | "@babel/code-frame": "^7.18.6", 392 | "@babel/parser": "^7.18.6", 393 | "@babel/types": "^7.18.6" 394 | }, 395 | "engines": { 396 | "node": ">=6.9.0" 397 | } 398 | }, 399 | "node_modules/@babel/traverse": { 400 | "version": "7.18.8", 401 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.8.tgz", 402 | "integrity": "sha512-UNg/AcSySJYR/+mIcJQDCv00T+AqRO7j/ZEJLzpaYtgM48rMg5MnkJgyNqkzo88+p4tfRvZJCEiwwfG6h4jkRg==", 403 | "dev": true, 404 | "dependencies": { 405 | "@babel/code-frame": "^7.18.6", 406 | "@babel/generator": "^7.18.7", 407 | "@babel/helper-environment-visitor": "^7.18.6", 408 | "@babel/helper-function-name": "^7.18.6", 409 | "@babel/helper-hoist-variables": "^7.18.6", 410 | "@babel/helper-split-export-declaration": "^7.18.6", 411 | "@babel/parser": "^7.18.8", 412 | "@babel/types": "^7.18.8", 413 | "debug": "^4.1.0", 414 | "globals": "^11.1.0" 415 | }, 416 | "engines": { 417 | "node": ">=6.9.0" 418 | } 419 | }, 420 | "node_modules/@babel/types": { 421 | "version": "7.18.8", 422 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.8.tgz", 423 | "integrity": "sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw==", 424 | "dev": true, 425 | "dependencies": { 426 | "@babel/helper-validator-identifier": "^7.18.6", 427 | "to-fast-properties": "^2.0.0" 428 | }, 429 | "engines": { 430 | "node": ">=6.9.0" 431 | } 432 | }, 433 | "node_modules/@fortawesome/fontawesome-common-types": { 434 | "version": "6.2.1", 435 | "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", 436 | "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==", 437 | "hasInstallScript": true, 438 | "engines": { 439 | "node": ">=6" 440 | } 441 | }, 442 | "node_modules/@fortawesome/fontawesome-svg-core": { 443 | "version": "6.2.1", 444 | "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz", 445 | "integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==", 446 | "hasInstallScript": true, 447 | "dependencies": { 448 | "@fortawesome/fontawesome-common-types": "6.2.1" 449 | }, 450 | "engines": { 451 | "node": ">=6" 452 | } 453 | }, 454 | "node_modules/@fortawesome/free-brands-svg-icons": { 455 | "version": "6.2.1", 456 | "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.1.tgz", 457 | "integrity": "sha512-L8l4MfdHPmZlJ72PvzdfwOwbwcCAL0vx48tJRnI6u1PJXh+j2f3yDoKyQgO3qjEsgD5Fr2tQV/cPP8F/k6aUig==", 458 | "hasInstallScript": true, 459 | "dependencies": { 460 | "@fortawesome/fontawesome-common-types": "6.2.1" 461 | }, 462 | "engines": { 463 | "node": ">=6" 464 | } 465 | }, 466 | "node_modules/@fortawesome/free-solid-svg-icons": { 467 | "version": "6.2.1", 468 | "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz", 469 | "integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==", 470 | "hasInstallScript": true, 471 | "dependencies": { 472 | "@fortawesome/fontawesome-common-types": "6.2.1" 473 | }, 474 | "engines": { 475 | "node": ">=6" 476 | } 477 | }, 478 | "node_modules/@fortawesome/react-fontawesome": { 479 | "version": "0.2.0", 480 | "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", 481 | "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", 482 | "dependencies": { 483 | "prop-types": "^15.8.1" 484 | }, 485 | "peerDependencies": { 486 | "@fortawesome/fontawesome-svg-core": "~1 || ~6", 487 | "react": ">=16.3" 488 | } 489 | }, 490 | "node_modules/@jridgewell/gen-mapping": { 491 | "version": "0.1.1", 492 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", 493 | "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", 494 | "dev": true, 495 | "dependencies": { 496 | "@jridgewell/set-array": "^1.0.0", 497 | "@jridgewell/sourcemap-codec": "^1.4.10" 498 | }, 499 | "engines": { 500 | "node": ">=6.0.0" 501 | } 502 | }, 503 | "node_modules/@jridgewell/resolve-uri": { 504 | "version": "3.1.0", 505 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 506 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 507 | "dev": true, 508 | "engines": { 509 | "node": ">=6.0.0" 510 | } 511 | }, 512 | "node_modules/@jridgewell/set-array": { 513 | "version": "1.1.2", 514 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 515 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 516 | "dev": true, 517 | "engines": { 518 | "node": ">=6.0.0" 519 | } 520 | }, 521 | "node_modules/@jridgewell/sourcemap-codec": { 522 | "version": "1.4.14", 523 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 524 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 525 | "dev": true 526 | }, 527 | "node_modules/@jridgewell/trace-mapping": { 528 | "version": "0.3.14", 529 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", 530 | "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", 531 | "dev": true, 532 | "dependencies": { 533 | "@jridgewell/resolve-uri": "^3.0.3", 534 | "@jridgewell/sourcemap-codec": "^1.4.10" 535 | } 536 | }, 537 | "node_modules/@rollup/pluginutils": { 538 | "version": "4.2.1", 539 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 540 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 541 | "dev": true, 542 | "dependencies": { 543 | "estree-walker": "^2.0.1", 544 | "picomatch": "^2.2.2" 545 | }, 546 | "engines": { 547 | "node": ">= 8.0.0" 548 | } 549 | }, 550 | "node_modules/@types/prop-types": { 551 | "version": "15.7.5", 552 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", 553 | "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", 554 | "dev": true 555 | }, 556 | "node_modules/@types/react": { 557 | "version": "18.0.15", 558 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz", 559 | "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==", 560 | "dev": true, 561 | "dependencies": { 562 | "@types/prop-types": "*", 563 | "@types/scheduler": "*", 564 | "csstype": "^3.0.2" 565 | } 566 | }, 567 | "node_modules/@types/react-dom": { 568 | "version": "18.0.6", 569 | "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", 570 | "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", 571 | "dev": true, 572 | "dependencies": { 573 | "@types/react": "*" 574 | } 575 | }, 576 | "node_modules/@types/scheduler": { 577 | "version": "0.16.2", 578 | "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", 579 | "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", 580 | "dev": true 581 | }, 582 | "node_modules/@vitejs/plugin-react": { 583 | "version": "1.3.2", 584 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz", 585 | "integrity": "sha512-aurBNmMo0kz1O4qRoY+FM4epSA39y3ShWGuqfLRA/3z0oEJAdtoSfgA3aO98/PCCHAqMaduLxIxErWrVKIFzXA==", 586 | "dev": true, 587 | "dependencies": { 588 | "@babel/core": "^7.17.10", 589 | "@babel/plugin-transform-react-jsx": "^7.17.3", 590 | "@babel/plugin-transform-react-jsx-development": "^7.16.7", 591 | "@babel/plugin-transform-react-jsx-self": "^7.16.7", 592 | "@babel/plugin-transform-react-jsx-source": "^7.16.7", 593 | "@rollup/pluginutils": "^4.2.1", 594 | "react-refresh": "^0.13.0", 595 | "resolve": "^1.22.0" 596 | }, 597 | "engines": { 598 | "node": ">=12.0.0" 599 | } 600 | }, 601 | "node_modules/ansi-styles": { 602 | "version": "3.2.1", 603 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 604 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 605 | "dev": true, 606 | "dependencies": { 607 | "color-convert": "^1.9.0" 608 | }, 609 | "engines": { 610 | "node": ">=4" 611 | } 612 | }, 613 | "node_modules/browserslist": { 614 | "version": "4.21.1", 615 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz", 616 | "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==", 617 | "dev": true, 618 | "funding": [ 619 | { 620 | "type": "opencollective", 621 | "url": "https://opencollective.com/browserslist" 622 | }, 623 | { 624 | "type": "tidelift", 625 | "url": "https://tidelift.com/funding/github/npm/browserslist" 626 | } 627 | ], 628 | "dependencies": { 629 | "caniuse-lite": "^1.0.30001359", 630 | "electron-to-chromium": "^1.4.172", 631 | "node-releases": "^2.0.5", 632 | "update-browserslist-db": "^1.0.4" 633 | }, 634 | "bin": { 635 | "browserslist": "cli.js" 636 | }, 637 | "engines": { 638 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 639 | } 640 | }, 641 | "node_modules/caniuse-lite": { 642 | "version": "1.0.30001364", 643 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001364.tgz", 644 | "integrity": "sha512-9O0xzV3wVyX0SlegIQ6knz+okhBB5pE0PC40MNdwcipjwpxoUEHL24uJ+gG42cgklPjfO5ZjZPme9FTSN3QT2Q==", 645 | "dev": true, 646 | "funding": [ 647 | { 648 | "type": "opencollective", 649 | "url": "https://opencollective.com/browserslist" 650 | }, 651 | { 652 | "type": "tidelift", 653 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 654 | } 655 | ] 656 | }, 657 | "node_modules/chalk": { 658 | "version": "2.4.2", 659 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 660 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 661 | "dev": true, 662 | "dependencies": { 663 | "ansi-styles": "^3.2.1", 664 | "escape-string-regexp": "^1.0.5", 665 | "supports-color": "^5.3.0" 666 | }, 667 | "engines": { 668 | "node": ">=4" 669 | } 670 | }, 671 | "node_modules/color-convert": { 672 | "version": "1.9.3", 673 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 674 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 675 | "dev": true, 676 | "dependencies": { 677 | "color-name": "1.1.3" 678 | } 679 | }, 680 | "node_modules/color-name": { 681 | "version": "1.1.3", 682 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 683 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", 684 | "dev": true 685 | }, 686 | "node_modules/convert-source-map": { 687 | "version": "1.8.0", 688 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", 689 | "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", 690 | "dev": true, 691 | "dependencies": { 692 | "safe-buffer": "~5.1.1" 693 | } 694 | }, 695 | "node_modules/csstype": { 696 | "version": "3.1.0", 697 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", 698 | "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==", 699 | "dev": true 700 | }, 701 | "node_modules/debug": { 702 | "version": "4.3.4", 703 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 704 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 705 | "dev": true, 706 | "dependencies": { 707 | "ms": "2.1.2" 708 | }, 709 | "engines": { 710 | "node": ">=6.0" 711 | }, 712 | "peerDependenciesMeta": { 713 | "supports-color": { 714 | "optional": true 715 | } 716 | } 717 | }, 718 | "node_modules/electron-to-chromium": { 719 | "version": "1.4.185", 720 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.185.tgz", 721 | "integrity": "sha512-9kV/isoOGpKkBt04yYNaSWIBn3187Q5VZRtoReq8oz5NY/A4XmU6cAoqgQlDp7kKJCZMRjWZ8nsQyxfpFHvfyw==", 722 | "dev": true 723 | }, 724 | "node_modules/esbuild": { 725 | "version": "0.14.48", 726 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", 727 | "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", 728 | "dev": true, 729 | "hasInstallScript": true, 730 | "bin": { 731 | "esbuild": "bin/esbuild" 732 | }, 733 | "engines": { 734 | "node": ">=12" 735 | }, 736 | "optionalDependencies": { 737 | "esbuild-android-64": "0.14.48", 738 | "esbuild-android-arm64": "0.14.48", 739 | "esbuild-darwin-64": "0.14.48", 740 | "esbuild-darwin-arm64": "0.14.48", 741 | "esbuild-freebsd-64": "0.14.48", 742 | "esbuild-freebsd-arm64": "0.14.48", 743 | "esbuild-linux-32": "0.14.48", 744 | "esbuild-linux-64": "0.14.48", 745 | "esbuild-linux-arm": "0.14.48", 746 | "esbuild-linux-arm64": "0.14.48", 747 | "esbuild-linux-mips64le": "0.14.48", 748 | "esbuild-linux-ppc64le": "0.14.48", 749 | "esbuild-linux-riscv64": "0.14.48", 750 | "esbuild-linux-s390x": "0.14.48", 751 | "esbuild-netbsd-64": "0.14.48", 752 | "esbuild-openbsd-64": "0.14.48", 753 | "esbuild-sunos-64": "0.14.48", 754 | "esbuild-windows-32": "0.14.48", 755 | "esbuild-windows-64": "0.14.48", 756 | "esbuild-windows-arm64": "0.14.48" 757 | } 758 | }, 759 | "node_modules/esbuild-android-64": { 760 | "version": "0.14.48", 761 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", 762 | "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", 763 | "cpu": [ 764 | "x64" 765 | ], 766 | "dev": true, 767 | "optional": true, 768 | "os": [ 769 | "android" 770 | ], 771 | "engines": { 772 | "node": ">=12" 773 | } 774 | }, 775 | "node_modules/esbuild-android-arm64": { 776 | "version": "0.14.48", 777 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", 778 | "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", 779 | "cpu": [ 780 | "arm64" 781 | ], 782 | "dev": true, 783 | "optional": true, 784 | "os": [ 785 | "android" 786 | ], 787 | "engines": { 788 | "node": ">=12" 789 | } 790 | }, 791 | "node_modules/esbuild-darwin-64": { 792 | "version": "0.14.48", 793 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", 794 | "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", 795 | "cpu": [ 796 | "x64" 797 | ], 798 | "dev": true, 799 | "optional": true, 800 | "os": [ 801 | "darwin" 802 | ], 803 | "engines": { 804 | "node": ">=12" 805 | } 806 | }, 807 | "node_modules/esbuild-darwin-arm64": { 808 | "version": "0.14.48", 809 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", 810 | "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", 811 | "cpu": [ 812 | "arm64" 813 | ], 814 | "dev": true, 815 | "optional": true, 816 | "os": [ 817 | "darwin" 818 | ], 819 | "engines": { 820 | "node": ">=12" 821 | } 822 | }, 823 | "node_modules/esbuild-freebsd-64": { 824 | "version": "0.14.48", 825 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", 826 | "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", 827 | "cpu": [ 828 | "x64" 829 | ], 830 | "dev": true, 831 | "optional": true, 832 | "os": [ 833 | "freebsd" 834 | ], 835 | "engines": { 836 | "node": ">=12" 837 | } 838 | }, 839 | "node_modules/esbuild-freebsd-arm64": { 840 | "version": "0.14.48", 841 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", 842 | "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", 843 | "cpu": [ 844 | "arm64" 845 | ], 846 | "dev": true, 847 | "optional": true, 848 | "os": [ 849 | "freebsd" 850 | ], 851 | "engines": { 852 | "node": ">=12" 853 | } 854 | }, 855 | "node_modules/esbuild-linux-32": { 856 | "version": "0.14.48", 857 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", 858 | "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", 859 | "cpu": [ 860 | "ia32" 861 | ], 862 | "dev": true, 863 | "optional": true, 864 | "os": [ 865 | "linux" 866 | ], 867 | "engines": { 868 | "node": ">=12" 869 | } 870 | }, 871 | "node_modules/esbuild-linux-64": { 872 | "version": "0.14.48", 873 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", 874 | "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", 875 | "cpu": [ 876 | "x64" 877 | ], 878 | "dev": true, 879 | "optional": true, 880 | "os": [ 881 | "linux" 882 | ], 883 | "engines": { 884 | "node": ">=12" 885 | } 886 | }, 887 | "node_modules/esbuild-linux-arm": { 888 | "version": "0.14.48", 889 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", 890 | "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", 891 | "cpu": [ 892 | "arm" 893 | ], 894 | "dev": true, 895 | "optional": true, 896 | "os": [ 897 | "linux" 898 | ], 899 | "engines": { 900 | "node": ">=12" 901 | } 902 | }, 903 | "node_modules/esbuild-linux-arm64": { 904 | "version": "0.14.48", 905 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", 906 | "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", 907 | "cpu": [ 908 | "arm64" 909 | ], 910 | "dev": true, 911 | "optional": true, 912 | "os": [ 913 | "linux" 914 | ], 915 | "engines": { 916 | "node": ">=12" 917 | } 918 | }, 919 | "node_modules/esbuild-linux-mips64le": { 920 | "version": "0.14.48", 921 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", 922 | "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", 923 | "cpu": [ 924 | "mips64el" 925 | ], 926 | "dev": true, 927 | "optional": true, 928 | "os": [ 929 | "linux" 930 | ], 931 | "engines": { 932 | "node": ">=12" 933 | } 934 | }, 935 | "node_modules/esbuild-linux-ppc64le": { 936 | "version": "0.14.48", 937 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", 938 | "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", 939 | "cpu": [ 940 | "ppc64" 941 | ], 942 | "dev": true, 943 | "optional": true, 944 | "os": [ 945 | "linux" 946 | ], 947 | "engines": { 948 | "node": ">=12" 949 | } 950 | }, 951 | "node_modules/esbuild-linux-riscv64": { 952 | "version": "0.14.48", 953 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", 954 | "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", 955 | "cpu": [ 956 | "riscv64" 957 | ], 958 | "dev": true, 959 | "optional": true, 960 | "os": [ 961 | "linux" 962 | ], 963 | "engines": { 964 | "node": ">=12" 965 | } 966 | }, 967 | "node_modules/esbuild-linux-s390x": { 968 | "version": "0.14.48", 969 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", 970 | "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", 971 | "cpu": [ 972 | "s390x" 973 | ], 974 | "dev": true, 975 | "optional": true, 976 | "os": [ 977 | "linux" 978 | ], 979 | "engines": { 980 | "node": ">=12" 981 | } 982 | }, 983 | "node_modules/esbuild-netbsd-64": { 984 | "version": "0.14.48", 985 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", 986 | "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", 987 | "cpu": [ 988 | "x64" 989 | ], 990 | "dev": true, 991 | "optional": true, 992 | "os": [ 993 | "netbsd" 994 | ], 995 | "engines": { 996 | "node": ">=12" 997 | } 998 | }, 999 | "node_modules/esbuild-openbsd-64": { 1000 | "version": "0.14.48", 1001 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", 1002 | "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", 1003 | "cpu": [ 1004 | "x64" 1005 | ], 1006 | "dev": true, 1007 | "optional": true, 1008 | "os": [ 1009 | "openbsd" 1010 | ], 1011 | "engines": { 1012 | "node": ">=12" 1013 | } 1014 | }, 1015 | "node_modules/esbuild-sunos-64": { 1016 | "version": "0.14.48", 1017 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", 1018 | "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", 1019 | "cpu": [ 1020 | "x64" 1021 | ], 1022 | "dev": true, 1023 | "optional": true, 1024 | "os": [ 1025 | "sunos" 1026 | ], 1027 | "engines": { 1028 | "node": ">=12" 1029 | } 1030 | }, 1031 | "node_modules/esbuild-windows-32": { 1032 | "version": "0.14.48", 1033 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", 1034 | "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", 1035 | "cpu": [ 1036 | "ia32" 1037 | ], 1038 | "dev": true, 1039 | "optional": true, 1040 | "os": [ 1041 | "win32" 1042 | ], 1043 | "engines": { 1044 | "node": ">=12" 1045 | } 1046 | }, 1047 | "node_modules/esbuild-windows-64": { 1048 | "version": "0.14.48", 1049 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", 1050 | "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", 1051 | "cpu": [ 1052 | "x64" 1053 | ], 1054 | "dev": true, 1055 | "optional": true, 1056 | "os": [ 1057 | "win32" 1058 | ], 1059 | "engines": { 1060 | "node": ">=12" 1061 | } 1062 | }, 1063 | "node_modules/esbuild-windows-arm64": { 1064 | "version": "0.14.48", 1065 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", 1066 | "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", 1067 | "cpu": [ 1068 | "arm64" 1069 | ], 1070 | "dev": true, 1071 | "optional": true, 1072 | "os": [ 1073 | "win32" 1074 | ], 1075 | "engines": { 1076 | "node": ">=12" 1077 | } 1078 | }, 1079 | "node_modules/escalade": { 1080 | "version": "3.1.1", 1081 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1082 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 1083 | "dev": true, 1084 | "engines": { 1085 | "node": ">=6" 1086 | } 1087 | }, 1088 | "node_modules/escape-string-regexp": { 1089 | "version": "1.0.5", 1090 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 1091 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 1092 | "dev": true, 1093 | "engines": { 1094 | "node": ">=0.8.0" 1095 | } 1096 | }, 1097 | "node_modules/estree-walker": { 1098 | "version": "2.0.2", 1099 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 1100 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 1101 | "dev": true 1102 | }, 1103 | "node_modules/fsevents": { 1104 | "version": "2.3.2", 1105 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1106 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1107 | "dev": true, 1108 | "hasInstallScript": true, 1109 | "optional": true, 1110 | "os": [ 1111 | "darwin" 1112 | ], 1113 | "engines": { 1114 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1115 | } 1116 | }, 1117 | "node_modules/function-bind": { 1118 | "version": "1.1.1", 1119 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1120 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 1121 | "dev": true 1122 | }, 1123 | "node_modules/gensync": { 1124 | "version": "1.0.0-beta.2", 1125 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 1126 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", 1127 | "dev": true, 1128 | "engines": { 1129 | "node": ">=6.9.0" 1130 | } 1131 | }, 1132 | "node_modules/globals": { 1133 | "version": "11.12.0", 1134 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 1135 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", 1136 | "dev": true, 1137 | "engines": { 1138 | "node": ">=4" 1139 | } 1140 | }, 1141 | "node_modules/has": { 1142 | "version": "1.0.3", 1143 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1144 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1145 | "dev": true, 1146 | "dependencies": { 1147 | "function-bind": "^1.1.1" 1148 | }, 1149 | "engines": { 1150 | "node": ">= 0.4.0" 1151 | } 1152 | }, 1153 | "node_modules/has-flag": { 1154 | "version": "3.0.0", 1155 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1156 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 1157 | "dev": true, 1158 | "engines": { 1159 | "node": ">=4" 1160 | } 1161 | }, 1162 | "node_modules/immer": { 1163 | "version": "9.0.16", 1164 | "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", 1165 | "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", 1166 | "funding": { 1167 | "type": "opencollective", 1168 | "url": "https://opencollective.com/immer" 1169 | } 1170 | }, 1171 | "node_modules/is-core-module": { 1172 | "version": "2.9.0", 1173 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", 1174 | "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", 1175 | "dev": true, 1176 | "dependencies": { 1177 | "has": "^1.0.3" 1178 | }, 1179 | "funding": { 1180 | "url": "https://github.com/sponsors/ljharb" 1181 | } 1182 | }, 1183 | "node_modules/js-tokens": { 1184 | "version": "4.0.0", 1185 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1186 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 1187 | }, 1188 | "node_modules/jsesc": { 1189 | "version": "2.5.2", 1190 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", 1191 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", 1192 | "dev": true, 1193 | "bin": { 1194 | "jsesc": "bin/jsesc" 1195 | }, 1196 | "engines": { 1197 | "node": ">=4" 1198 | } 1199 | }, 1200 | "node_modules/json5": { 1201 | "version": "2.2.1", 1202 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", 1203 | "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", 1204 | "dev": true, 1205 | "bin": { 1206 | "json5": "lib/cli.js" 1207 | }, 1208 | "engines": { 1209 | "node": ">=6" 1210 | } 1211 | }, 1212 | "node_modules/loose-envify": { 1213 | "version": "1.4.0", 1214 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 1215 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 1216 | "dependencies": { 1217 | "js-tokens": "^3.0.0 || ^4.0.0" 1218 | }, 1219 | "bin": { 1220 | "loose-envify": "cli.js" 1221 | } 1222 | }, 1223 | "node_modules/ms": { 1224 | "version": "2.1.2", 1225 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1226 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 1227 | "dev": true 1228 | }, 1229 | "node_modules/nanoid": { 1230 | "version": "3.3.4", 1231 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 1232 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 1233 | "dev": true, 1234 | "bin": { 1235 | "nanoid": "bin/nanoid.cjs" 1236 | }, 1237 | "engines": { 1238 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1239 | } 1240 | }, 1241 | "node_modules/node-releases": { 1242 | "version": "2.0.6", 1243 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", 1244 | "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", 1245 | "dev": true 1246 | }, 1247 | "node_modules/object-assign": { 1248 | "version": "4.1.1", 1249 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1250 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 1251 | "engines": { 1252 | "node": ">=0.10.0" 1253 | } 1254 | }, 1255 | "node_modules/path-parse": { 1256 | "version": "1.0.7", 1257 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 1258 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 1259 | "dev": true 1260 | }, 1261 | "node_modules/picocolors": { 1262 | "version": "1.0.0", 1263 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1264 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 1265 | "dev": true 1266 | }, 1267 | "node_modules/picomatch": { 1268 | "version": "2.3.1", 1269 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1270 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1271 | "dev": true, 1272 | "engines": { 1273 | "node": ">=8.6" 1274 | }, 1275 | "funding": { 1276 | "url": "https://github.com/sponsors/jonschlinkert" 1277 | } 1278 | }, 1279 | "node_modules/postcss": { 1280 | "version": "8.4.14", 1281 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", 1282 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", 1283 | "dev": true, 1284 | "funding": [ 1285 | { 1286 | "type": "opencollective", 1287 | "url": "https://opencollective.com/postcss/" 1288 | }, 1289 | { 1290 | "type": "tidelift", 1291 | "url": "https://tidelift.com/funding/github/npm/postcss" 1292 | } 1293 | ], 1294 | "dependencies": { 1295 | "nanoid": "^3.3.4", 1296 | "picocolors": "^1.0.0", 1297 | "source-map-js": "^1.0.2" 1298 | }, 1299 | "engines": { 1300 | "node": "^10 || ^12 || >=14" 1301 | } 1302 | }, 1303 | "node_modules/prop-types": { 1304 | "version": "15.8.1", 1305 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", 1306 | "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", 1307 | "dependencies": { 1308 | "loose-envify": "^1.4.0", 1309 | "object-assign": "^4.1.1", 1310 | "react-is": "^16.13.1" 1311 | } 1312 | }, 1313 | "node_modules/react": { 1314 | "version": "18.2.0", 1315 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", 1316 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", 1317 | "dependencies": { 1318 | "loose-envify": "^1.1.0" 1319 | }, 1320 | "engines": { 1321 | "node": ">=0.10.0" 1322 | } 1323 | }, 1324 | "node_modules/react-device-detect": { 1325 | "version": "2.2.3", 1326 | "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz", 1327 | "integrity": "sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==", 1328 | "dependencies": { 1329 | "ua-parser-js": "^1.0.33" 1330 | }, 1331 | "peerDependencies": { 1332 | "react": ">= 0.14.0", 1333 | "react-dom": ">= 0.14.0" 1334 | } 1335 | }, 1336 | "node_modules/react-dom": { 1337 | "version": "18.2.0", 1338 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", 1339 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", 1340 | "dependencies": { 1341 | "loose-envify": "^1.1.0", 1342 | "scheduler": "^0.23.0" 1343 | }, 1344 | "peerDependencies": { 1345 | "react": "^18.2.0" 1346 | } 1347 | }, 1348 | "node_modules/react-is": { 1349 | "version": "16.13.1", 1350 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", 1351 | "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" 1352 | }, 1353 | "node_modules/react-refresh": { 1354 | "version": "0.13.0", 1355 | "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.13.0.tgz", 1356 | "integrity": "sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==", 1357 | "dev": true, 1358 | "engines": { 1359 | "node": ">=0.10.0" 1360 | } 1361 | }, 1362 | "node_modules/resolve": { 1363 | "version": "1.22.1", 1364 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 1365 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 1366 | "dev": true, 1367 | "dependencies": { 1368 | "is-core-module": "^2.9.0", 1369 | "path-parse": "^1.0.7", 1370 | "supports-preserve-symlinks-flag": "^1.0.0" 1371 | }, 1372 | "bin": { 1373 | "resolve": "bin/resolve" 1374 | }, 1375 | "funding": { 1376 | "url": "https://github.com/sponsors/ljharb" 1377 | } 1378 | }, 1379 | "node_modules/rollup": { 1380 | "version": "2.76.0", 1381 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.76.0.tgz", 1382 | "integrity": "sha512-9jwRIEY1jOzKLj3nsY/yot41r19ITdQrhs+q3ggNWhr9TQgduHqANvPpS32RNpzGklJu3G1AJfvlZLi/6wFgWA==", 1383 | "dev": true, 1384 | "bin": { 1385 | "rollup": "dist/bin/rollup" 1386 | }, 1387 | "engines": { 1388 | "node": ">=10.0.0" 1389 | }, 1390 | "optionalDependencies": { 1391 | "fsevents": "~2.3.2" 1392 | } 1393 | }, 1394 | "node_modules/safe-buffer": { 1395 | "version": "5.1.2", 1396 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1397 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1398 | "dev": true 1399 | }, 1400 | "node_modules/scheduler": { 1401 | "version": "0.23.0", 1402 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", 1403 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", 1404 | "dependencies": { 1405 | "loose-envify": "^1.1.0" 1406 | } 1407 | }, 1408 | "node_modules/semver": { 1409 | "version": "6.3.0", 1410 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1411 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1412 | "dev": true, 1413 | "bin": { 1414 | "semver": "bin/semver.js" 1415 | } 1416 | }, 1417 | "node_modules/source-map-js": { 1418 | "version": "1.0.2", 1419 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1420 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1421 | "dev": true, 1422 | "engines": { 1423 | "node": ">=0.10.0" 1424 | } 1425 | }, 1426 | "node_modules/supports-color": { 1427 | "version": "5.5.0", 1428 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1429 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1430 | "dev": true, 1431 | "dependencies": { 1432 | "has-flag": "^3.0.0" 1433 | }, 1434 | "engines": { 1435 | "node": ">=4" 1436 | } 1437 | }, 1438 | "node_modules/supports-preserve-symlinks-flag": { 1439 | "version": "1.0.0", 1440 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1441 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1442 | "dev": true, 1443 | "engines": { 1444 | "node": ">= 0.4" 1445 | }, 1446 | "funding": { 1447 | "url": "https://github.com/sponsors/ljharb" 1448 | } 1449 | }, 1450 | "node_modules/to-fast-properties": { 1451 | "version": "2.0.0", 1452 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 1453 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", 1454 | "dev": true, 1455 | "engines": { 1456 | "node": ">=4" 1457 | } 1458 | }, 1459 | "node_modules/typescript": { 1460 | "version": "4.7.4", 1461 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", 1462 | "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", 1463 | "dev": true, 1464 | "bin": { 1465 | "tsc": "bin/tsc", 1466 | "tsserver": "bin/tsserver" 1467 | }, 1468 | "engines": { 1469 | "node": ">=4.2.0" 1470 | } 1471 | }, 1472 | "node_modules/ua-parser-js": { 1473 | "version": "1.0.35", 1474 | "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", 1475 | "integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==", 1476 | "funding": [ 1477 | { 1478 | "type": "opencollective", 1479 | "url": "https://opencollective.com/ua-parser-js" 1480 | }, 1481 | { 1482 | "type": "paypal", 1483 | "url": "https://paypal.me/faisalman" 1484 | } 1485 | ], 1486 | "engines": { 1487 | "node": "*" 1488 | } 1489 | }, 1490 | "node_modules/update-browserslist-db": { 1491 | "version": "1.0.4", 1492 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz", 1493 | "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==", 1494 | "dev": true, 1495 | "funding": [ 1496 | { 1497 | "type": "opencollective", 1498 | "url": "https://opencollective.com/browserslist" 1499 | }, 1500 | { 1501 | "type": "tidelift", 1502 | "url": "https://tidelift.com/funding/github/npm/browserslist" 1503 | } 1504 | ], 1505 | "dependencies": { 1506 | "escalade": "^3.1.1", 1507 | "picocolors": "^1.0.0" 1508 | }, 1509 | "bin": { 1510 | "browserslist-lint": "cli.js" 1511 | }, 1512 | "peerDependencies": { 1513 | "browserslist": ">= 4.21.0" 1514 | } 1515 | }, 1516 | "node_modules/vite": { 1517 | "version": "2.9.14", 1518 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.14.tgz", 1519 | "integrity": "sha512-P/UCjSpSMcE54r4mPak55hWAZPlyfS369svib/gpmz8/01L822lMPOJ/RYW6tLCe1RPvMvOsJ17erf55bKp4Hw==", 1520 | "dev": true, 1521 | "dependencies": { 1522 | "esbuild": "^0.14.27", 1523 | "postcss": "^8.4.13", 1524 | "resolve": "^1.22.0", 1525 | "rollup": "^2.59.0" 1526 | }, 1527 | "bin": { 1528 | "vite": "bin/vite.js" 1529 | }, 1530 | "engines": { 1531 | "node": ">=12.2.0" 1532 | }, 1533 | "optionalDependencies": { 1534 | "fsevents": "~2.3.2" 1535 | }, 1536 | "peerDependencies": { 1537 | "less": "*", 1538 | "sass": "*", 1539 | "stylus": "*" 1540 | }, 1541 | "peerDependenciesMeta": { 1542 | "less": { 1543 | "optional": true 1544 | }, 1545 | "sass": { 1546 | "optional": true 1547 | }, 1548 | "stylus": { 1549 | "optional": true 1550 | } 1551 | } 1552 | } 1553 | }, 1554 | "dependencies": { 1555 | "@ampproject/remapping": { 1556 | "version": "2.2.0", 1557 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", 1558 | "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", 1559 | "dev": true, 1560 | "requires": { 1561 | "@jridgewell/gen-mapping": "^0.1.0", 1562 | "@jridgewell/trace-mapping": "^0.3.9" 1563 | } 1564 | }, 1565 | "@babel/code-frame": { 1566 | "version": "7.18.6", 1567 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", 1568 | "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", 1569 | "dev": true, 1570 | "requires": { 1571 | "@babel/highlight": "^7.18.6" 1572 | } 1573 | }, 1574 | "@babel/compat-data": { 1575 | "version": "7.18.8", 1576 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", 1577 | "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==", 1578 | "dev": true 1579 | }, 1580 | "@babel/core": { 1581 | "version": "7.18.6", 1582 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", 1583 | "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", 1584 | "dev": true, 1585 | "requires": { 1586 | "@ampproject/remapping": "^2.1.0", 1587 | "@babel/code-frame": "^7.18.6", 1588 | "@babel/generator": "^7.18.6", 1589 | "@babel/helper-compilation-targets": "^7.18.6", 1590 | "@babel/helper-module-transforms": "^7.18.6", 1591 | "@babel/helpers": "^7.18.6", 1592 | "@babel/parser": "^7.18.6", 1593 | "@babel/template": "^7.18.6", 1594 | "@babel/traverse": "^7.18.6", 1595 | "@babel/types": "^7.18.6", 1596 | "convert-source-map": "^1.7.0", 1597 | "debug": "^4.1.0", 1598 | "gensync": "^1.0.0-beta.2", 1599 | "json5": "^2.2.1", 1600 | "semver": "^6.3.0" 1601 | } 1602 | }, 1603 | "@babel/generator": { 1604 | "version": "7.18.7", 1605 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", 1606 | "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", 1607 | "dev": true, 1608 | "requires": { 1609 | "@babel/types": "^7.18.7", 1610 | "@jridgewell/gen-mapping": "^0.3.2", 1611 | "jsesc": "^2.5.1" 1612 | }, 1613 | "dependencies": { 1614 | "@jridgewell/gen-mapping": { 1615 | "version": "0.3.2", 1616 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", 1617 | "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", 1618 | "dev": true, 1619 | "requires": { 1620 | "@jridgewell/set-array": "^1.0.1", 1621 | "@jridgewell/sourcemap-codec": "^1.4.10", 1622 | "@jridgewell/trace-mapping": "^0.3.9" 1623 | } 1624 | } 1625 | } 1626 | }, 1627 | "@babel/helper-annotate-as-pure": { 1628 | "version": "7.18.6", 1629 | "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", 1630 | "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", 1631 | "dev": true, 1632 | "requires": { 1633 | "@babel/types": "^7.18.6" 1634 | } 1635 | }, 1636 | "@babel/helper-compilation-targets": { 1637 | "version": "7.18.6", 1638 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", 1639 | "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", 1640 | "dev": true, 1641 | "requires": { 1642 | "@babel/compat-data": "^7.18.6", 1643 | "@babel/helper-validator-option": "^7.18.6", 1644 | "browserslist": "^4.20.2", 1645 | "semver": "^6.3.0" 1646 | } 1647 | }, 1648 | "@babel/helper-environment-visitor": { 1649 | "version": "7.18.6", 1650 | "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", 1651 | "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==", 1652 | "dev": true 1653 | }, 1654 | "@babel/helper-function-name": { 1655 | "version": "7.18.6", 1656 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", 1657 | "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", 1658 | "dev": true, 1659 | "requires": { 1660 | "@babel/template": "^7.18.6", 1661 | "@babel/types": "^7.18.6" 1662 | } 1663 | }, 1664 | "@babel/helper-hoist-variables": { 1665 | "version": "7.18.6", 1666 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", 1667 | "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", 1668 | "dev": true, 1669 | "requires": { 1670 | "@babel/types": "^7.18.6" 1671 | } 1672 | }, 1673 | "@babel/helper-module-imports": { 1674 | "version": "7.18.6", 1675 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", 1676 | "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", 1677 | "dev": true, 1678 | "requires": { 1679 | "@babel/types": "^7.18.6" 1680 | } 1681 | }, 1682 | "@babel/helper-module-transforms": { 1683 | "version": "7.18.8", 1684 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.8.tgz", 1685 | "integrity": "sha512-che3jvZwIcZxrwh63VfnFTUzcAM9v/lznYkkRxIBGMPt1SudOKHAEec0SIRCfiuIzTcF7VGj/CaTT6gY4eWxvA==", 1686 | "dev": true, 1687 | "requires": { 1688 | "@babel/helper-environment-visitor": "^7.18.6", 1689 | "@babel/helper-module-imports": "^7.18.6", 1690 | "@babel/helper-simple-access": "^7.18.6", 1691 | "@babel/helper-split-export-declaration": "^7.18.6", 1692 | "@babel/helper-validator-identifier": "^7.18.6", 1693 | "@babel/template": "^7.18.6", 1694 | "@babel/traverse": "^7.18.8", 1695 | "@babel/types": "^7.18.8" 1696 | } 1697 | }, 1698 | "@babel/helper-plugin-utils": { 1699 | "version": "7.18.6", 1700 | "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", 1701 | "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==", 1702 | "dev": true 1703 | }, 1704 | "@babel/helper-simple-access": { 1705 | "version": "7.18.6", 1706 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", 1707 | "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", 1708 | "dev": true, 1709 | "requires": { 1710 | "@babel/types": "^7.18.6" 1711 | } 1712 | }, 1713 | "@babel/helper-split-export-declaration": { 1714 | "version": "7.18.6", 1715 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", 1716 | "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", 1717 | "dev": true, 1718 | "requires": { 1719 | "@babel/types": "^7.18.6" 1720 | } 1721 | }, 1722 | "@babel/helper-validator-identifier": { 1723 | "version": "7.18.6", 1724 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", 1725 | "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", 1726 | "dev": true 1727 | }, 1728 | "@babel/helper-validator-option": { 1729 | "version": "7.18.6", 1730 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", 1731 | "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", 1732 | "dev": true 1733 | }, 1734 | "@babel/helpers": { 1735 | "version": "7.18.6", 1736 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz", 1737 | "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==", 1738 | "dev": true, 1739 | "requires": { 1740 | "@babel/template": "^7.18.6", 1741 | "@babel/traverse": "^7.18.6", 1742 | "@babel/types": "^7.18.6" 1743 | } 1744 | }, 1745 | "@babel/highlight": { 1746 | "version": "7.18.6", 1747 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", 1748 | "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", 1749 | "dev": true, 1750 | "requires": { 1751 | "@babel/helper-validator-identifier": "^7.18.6", 1752 | "chalk": "^2.0.0", 1753 | "js-tokens": "^4.0.0" 1754 | } 1755 | }, 1756 | "@babel/parser": { 1757 | "version": "7.18.8", 1758 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.8.tgz", 1759 | "integrity": "sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA==", 1760 | "dev": true 1761 | }, 1762 | "@babel/plugin-syntax-jsx": { 1763 | "version": "7.18.6", 1764 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", 1765 | "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", 1766 | "dev": true, 1767 | "requires": { 1768 | "@babel/helper-plugin-utils": "^7.18.6" 1769 | } 1770 | }, 1771 | "@babel/plugin-transform-react-jsx": { 1772 | "version": "7.18.6", 1773 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz", 1774 | "integrity": "sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==", 1775 | "dev": true, 1776 | "requires": { 1777 | "@babel/helper-annotate-as-pure": "^7.18.6", 1778 | "@babel/helper-module-imports": "^7.18.6", 1779 | "@babel/helper-plugin-utils": "^7.18.6", 1780 | "@babel/plugin-syntax-jsx": "^7.18.6", 1781 | "@babel/types": "^7.18.6" 1782 | } 1783 | }, 1784 | "@babel/plugin-transform-react-jsx-development": { 1785 | "version": "7.18.6", 1786 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz", 1787 | "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==", 1788 | "dev": true, 1789 | "requires": { 1790 | "@babel/plugin-transform-react-jsx": "^7.18.6" 1791 | } 1792 | }, 1793 | "@babel/plugin-transform-react-jsx-self": { 1794 | "version": "7.18.6", 1795 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.18.6.tgz", 1796 | "integrity": "sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==", 1797 | "dev": true, 1798 | "requires": { 1799 | "@babel/helper-plugin-utils": "^7.18.6" 1800 | } 1801 | }, 1802 | "@babel/plugin-transform-react-jsx-source": { 1803 | "version": "7.18.6", 1804 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.18.6.tgz", 1805 | "integrity": "sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==", 1806 | "dev": true, 1807 | "requires": { 1808 | "@babel/helper-plugin-utils": "^7.18.6" 1809 | } 1810 | }, 1811 | "@babel/template": { 1812 | "version": "7.18.6", 1813 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", 1814 | "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", 1815 | "dev": true, 1816 | "requires": { 1817 | "@babel/code-frame": "^7.18.6", 1818 | "@babel/parser": "^7.18.6", 1819 | "@babel/types": "^7.18.6" 1820 | } 1821 | }, 1822 | "@babel/traverse": { 1823 | "version": "7.18.8", 1824 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.8.tgz", 1825 | "integrity": "sha512-UNg/AcSySJYR/+mIcJQDCv00T+AqRO7j/ZEJLzpaYtgM48rMg5MnkJgyNqkzo88+p4tfRvZJCEiwwfG6h4jkRg==", 1826 | "dev": true, 1827 | "requires": { 1828 | "@babel/code-frame": "^7.18.6", 1829 | "@babel/generator": "^7.18.7", 1830 | "@babel/helper-environment-visitor": "^7.18.6", 1831 | "@babel/helper-function-name": "^7.18.6", 1832 | "@babel/helper-hoist-variables": "^7.18.6", 1833 | "@babel/helper-split-export-declaration": "^7.18.6", 1834 | "@babel/parser": "^7.18.8", 1835 | "@babel/types": "^7.18.8", 1836 | "debug": "^4.1.0", 1837 | "globals": "^11.1.0" 1838 | } 1839 | }, 1840 | "@babel/types": { 1841 | "version": "7.18.8", 1842 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.8.tgz", 1843 | "integrity": "sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw==", 1844 | "dev": true, 1845 | "requires": { 1846 | "@babel/helper-validator-identifier": "^7.18.6", 1847 | "to-fast-properties": "^2.0.0" 1848 | } 1849 | }, 1850 | "@fortawesome/fontawesome-common-types": { 1851 | "version": "6.2.1", 1852 | "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.2.1.tgz", 1853 | "integrity": "sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==" 1854 | }, 1855 | "@fortawesome/fontawesome-svg-core": { 1856 | "version": "6.2.1", 1857 | "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.2.1.tgz", 1858 | "integrity": "sha512-HELwwbCz6C1XEcjzyT1Jugmz2NNklMrSPjZOWMlc+ZsHIVk+XOvOXLGGQtFBwSyqfJDNgRq4xBCwWOaZ/d9DEA==", 1859 | "requires": { 1860 | "@fortawesome/fontawesome-common-types": "6.2.1" 1861 | } 1862 | }, 1863 | "@fortawesome/free-brands-svg-icons": { 1864 | "version": "6.2.1", 1865 | "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.2.1.tgz", 1866 | "integrity": "sha512-L8l4MfdHPmZlJ72PvzdfwOwbwcCAL0vx48tJRnI6u1PJXh+j2f3yDoKyQgO3qjEsgD5Fr2tQV/cPP8F/k6aUig==", 1867 | "requires": { 1868 | "@fortawesome/fontawesome-common-types": "6.2.1" 1869 | } 1870 | }, 1871 | "@fortawesome/free-solid-svg-icons": { 1872 | "version": "6.2.1", 1873 | "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.2.1.tgz", 1874 | "integrity": "sha512-oKuqrP5jbfEPJWTij4sM+/RvgX+RMFwx3QZCZcK9PrBDgxC35zuc7AOFsyMjMd/PIFPeB2JxyqDr5zs/DZFPPw==", 1875 | "requires": { 1876 | "@fortawesome/fontawesome-common-types": "6.2.1" 1877 | } 1878 | }, 1879 | "@fortawesome/react-fontawesome": { 1880 | "version": "0.2.0", 1881 | "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz", 1882 | "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==", 1883 | "requires": { 1884 | "prop-types": "^15.8.1" 1885 | } 1886 | }, 1887 | "@jridgewell/gen-mapping": { 1888 | "version": "0.1.1", 1889 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", 1890 | "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", 1891 | "dev": true, 1892 | "requires": { 1893 | "@jridgewell/set-array": "^1.0.0", 1894 | "@jridgewell/sourcemap-codec": "^1.4.10" 1895 | } 1896 | }, 1897 | "@jridgewell/resolve-uri": { 1898 | "version": "3.1.0", 1899 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 1900 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 1901 | "dev": true 1902 | }, 1903 | "@jridgewell/set-array": { 1904 | "version": "1.1.2", 1905 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 1906 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 1907 | "dev": true 1908 | }, 1909 | "@jridgewell/sourcemap-codec": { 1910 | "version": "1.4.14", 1911 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 1912 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", 1913 | "dev": true 1914 | }, 1915 | "@jridgewell/trace-mapping": { 1916 | "version": "0.3.14", 1917 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", 1918 | "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", 1919 | "dev": true, 1920 | "requires": { 1921 | "@jridgewell/resolve-uri": "^3.0.3", 1922 | "@jridgewell/sourcemap-codec": "^1.4.10" 1923 | } 1924 | }, 1925 | "@rollup/pluginutils": { 1926 | "version": "4.2.1", 1927 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 1928 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 1929 | "dev": true, 1930 | "requires": { 1931 | "estree-walker": "^2.0.1", 1932 | "picomatch": "^2.2.2" 1933 | } 1934 | }, 1935 | "@types/prop-types": { 1936 | "version": "15.7.5", 1937 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", 1938 | "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", 1939 | "dev": true 1940 | }, 1941 | "@types/react": { 1942 | "version": "18.0.15", 1943 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz", 1944 | "integrity": "sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==", 1945 | "dev": true, 1946 | "requires": { 1947 | "@types/prop-types": "*", 1948 | "@types/scheduler": "*", 1949 | "csstype": "^3.0.2" 1950 | } 1951 | }, 1952 | "@types/react-dom": { 1953 | "version": "18.0.6", 1954 | "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", 1955 | "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", 1956 | "dev": true, 1957 | "requires": { 1958 | "@types/react": "*" 1959 | } 1960 | }, 1961 | "@types/scheduler": { 1962 | "version": "0.16.2", 1963 | "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", 1964 | "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", 1965 | "dev": true 1966 | }, 1967 | "@vitejs/plugin-react": { 1968 | "version": "1.3.2", 1969 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-1.3.2.tgz", 1970 | "integrity": "sha512-aurBNmMo0kz1O4qRoY+FM4epSA39y3ShWGuqfLRA/3z0oEJAdtoSfgA3aO98/PCCHAqMaduLxIxErWrVKIFzXA==", 1971 | "dev": true, 1972 | "requires": { 1973 | "@babel/core": "^7.17.10", 1974 | "@babel/plugin-transform-react-jsx": "^7.17.3", 1975 | "@babel/plugin-transform-react-jsx-development": "^7.16.7", 1976 | "@babel/plugin-transform-react-jsx-self": "^7.16.7", 1977 | "@babel/plugin-transform-react-jsx-source": "^7.16.7", 1978 | "@rollup/pluginutils": "^4.2.1", 1979 | "react-refresh": "^0.13.0", 1980 | "resolve": "^1.22.0" 1981 | } 1982 | }, 1983 | "ansi-styles": { 1984 | "version": "3.2.1", 1985 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 1986 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 1987 | "dev": true, 1988 | "requires": { 1989 | "color-convert": "^1.9.0" 1990 | } 1991 | }, 1992 | "browserslist": { 1993 | "version": "4.21.1", 1994 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz", 1995 | "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==", 1996 | "dev": true, 1997 | "requires": { 1998 | "caniuse-lite": "^1.0.30001359", 1999 | "electron-to-chromium": "^1.4.172", 2000 | "node-releases": "^2.0.5", 2001 | "update-browserslist-db": "^1.0.4" 2002 | } 2003 | }, 2004 | "caniuse-lite": { 2005 | "version": "1.0.30001364", 2006 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001364.tgz", 2007 | "integrity": "sha512-9O0xzV3wVyX0SlegIQ6knz+okhBB5pE0PC40MNdwcipjwpxoUEHL24uJ+gG42cgklPjfO5ZjZPme9FTSN3QT2Q==", 2008 | "dev": true 2009 | }, 2010 | "chalk": { 2011 | "version": "2.4.2", 2012 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 2013 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 2014 | "dev": true, 2015 | "requires": { 2016 | "ansi-styles": "^3.2.1", 2017 | "escape-string-regexp": "^1.0.5", 2018 | "supports-color": "^5.3.0" 2019 | } 2020 | }, 2021 | "color-convert": { 2022 | "version": "1.9.3", 2023 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 2024 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 2025 | "dev": true, 2026 | "requires": { 2027 | "color-name": "1.1.3" 2028 | } 2029 | }, 2030 | "color-name": { 2031 | "version": "1.1.3", 2032 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 2033 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", 2034 | "dev": true 2035 | }, 2036 | "convert-source-map": { 2037 | "version": "1.8.0", 2038 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", 2039 | "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", 2040 | "dev": true, 2041 | "requires": { 2042 | "safe-buffer": "~5.1.1" 2043 | } 2044 | }, 2045 | "csstype": { 2046 | "version": "3.1.0", 2047 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", 2048 | "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==", 2049 | "dev": true 2050 | }, 2051 | "debug": { 2052 | "version": "4.3.4", 2053 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 2054 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 2055 | "dev": true, 2056 | "requires": { 2057 | "ms": "2.1.2" 2058 | } 2059 | }, 2060 | "electron-to-chromium": { 2061 | "version": "1.4.185", 2062 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.185.tgz", 2063 | "integrity": "sha512-9kV/isoOGpKkBt04yYNaSWIBn3187Q5VZRtoReq8oz5NY/A4XmU6cAoqgQlDp7kKJCZMRjWZ8nsQyxfpFHvfyw==", 2064 | "dev": true 2065 | }, 2066 | "esbuild": { 2067 | "version": "0.14.48", 2068 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", 2069 | "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", 2070 | "dev": true, 2071 | "requires": { 2072 | "esbuild-android-64": "0.14.48", 2073 | "esbuild-android-arm64": "0.14.48", 2074 | "esbuild-darwin-64": "0.14.48", 2075 | "esbuild-darwin-arm64": "0.14.48", 2076 | "esbuild-freebsd-64": "0.14.48", 2077 | "esbuild-freebsd-arm64": "0.14.48", 2078 | "esbuild-linux-32": "0.14.48", 2079 | "esbuild-linux-64": "0.14.48", 2080 | "esbuild-linux-arm": "0.14.48", 2081 | "esbuild-linux-arm64": "0.14.48", 2082 | "esbuild-linux-mips64le": "0.14.48", 2083 | "esbuild-linux-ppc64le": "0.14.48", 2084 | "esbuild-linux-riscv64": "0.14.48", 2085 | "esbuild-linux-s390x": "0.14.48", 2086 | "esbuild-netbsd-64": "0.14.48", 2087 | "esbuild-openbsd-64": "0.14.48", 2088 | "esbuild-sunos-64": "0.14.48", 2089 | "esbuild-windows-32": "0.14.48", 2090 | "esbuild-windows-64": "0.14.48", 2091 | "esbuild-windows-arm64": "0.14.48" 2092 | } 2093 | }, 2094 | "esbuild-android-64": { 2095 | "version": "0.14.48", 2096 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", 2097 | "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", 2098 | "dev": true, 2099 | "optional": true 2100 | }, 2101 | "esbuild-android-arm64": { 2102 | "version": "0.14.48", 2103 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", 2104 | "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", 2105 | "dev": true, 2106 | "optional": true 2107 | }, 2108 | "esbuild-darwin-64": { 2109 | "version": "0.14.48", 2110 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", 2111 | "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", 2112 | "dev": true, 2113 | "optional": true 2114 | }, 2115 | "esbuild-darwin-arm64": { 2116 | "version": "0.14.48", 2117 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", 2118 | "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", 2119 | "dev": true, 2120 | "optional": true 2121 | }, 2122 | "esbuild-freebsd-64": { 2123 | "version": "0.14.48", 2124 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", 2125 | "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", 2126 | "dev": true, 2127 | "optional": true 2128 | }, 2129 | "esbuild-freebsd-arm64": { 2130 | "version": "0.14.48", 2131 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", 2132 | "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", 2133 | "dev": true, 2134 | "optional": true 2135 | }, 2136 | "esbuild-linux-32": { 2137 | "version": "0.14.48", 2138 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", 2139 | "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", 2140 | "dev": true, 2141 | "optional": true 2142 | }, 2143 | "esbuild-linux-64": { 2144 | "version": "0.14.48", 2145 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", 2146 | "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", 2147 | "dev": true, 2148 | "optional": true 2149 | }, 2150 | "esbuild-linux-arm": { 2151 | "version": "0.14.48", 2152 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", 2153 | "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", 2154 | "dev": true, 2155 | "optional": true 2156 | }, 2157 | "esbuild-linux-arm64": { 2158 | "version": "0.14.48", 2159 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", 2160 | "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", 2161 | "dev": true, 2162 | "optional": true 2163 | }, 2164 | "esbuild-linux-mips64le": { 2165 | "version": "0.14.48", 2166 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", 2167 | "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", 2168 | "dev": true, 2169 | "optional": true 2170 | }, 2171 | "esbuild-linux-ppc64le": { 2172 | "version": "0.14.48", 2173 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", 2174 | "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", 2175 | "dev": true, 2176 | "optional": true 2177 | }, 2178 | "esbuild-linux-riscv64": { 2179 | "version": "0.14.48", 2180 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", 2181 | "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", 2182 | "dev": true, 2183 | "optional": true 2184 | }, 2185 | "esbuild-linux-s390x": { 2186 | "version": "0.14.48", 2187 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", 2188 | "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", 2189 | "dev": true, 2190 | "optional": true 2191 | }, 2192 | "esbuild-netbsd-64": { 2193 | "version": "0.14.48", 2194 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", 2195 | "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", 2196 | "dev": true, 2197 | "optional": true 2198 | }, 2199 | "esbuild-openbsd-64": { 2200 | "version": "0.14.48", 2201 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", 2202 | "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", 2203 | "dev": true, 2204 | "optional": true 2205 | }, 2206 | "esbuild-sunos-64": { 2207 | "version": "0.14.48", 2208 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", 2209 | "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", 2210 | "dev": true, 2211 | "optional": true 2212 | }, 2213 | "esbuild-windows-32": { 2214 | "version": "0.14.48", 2215 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", 2216 | "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", 2217 | "dev": true, 2218 | "optional": true 2219 | }, 2220 | "esbuild-windows-64": { 2221 | "version": "0.14.48", 2222 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", 2223 | "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", 2224 | "dev": true, 2225 | "optional": true 2226 | }, 2227 | "esbuild-windows-arm64": { 2228 | "version": "0.14.48", 2229 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", 2230 | "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", 2231 | "dev": true, 2232 | "optional": true 2233 | }, 2234 | "escalade": { 2235 | "version": "3.1.1", 2236 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 2237 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 2238 | "dev": true 2239 | }, 2240 | "escape-string-regexp": { 2241 | "version": "1.0.5", 2242 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 2243 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 2244 | "dev": true 2245 | }, 2246 | "estree-walker": { 2247 | "version": "2.0.2", 2248 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 2249 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 2250 | "dev": true 2251 | }, 2252 | "fsevents": { 2253 | "version": "2.3.2", 2254 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 2255 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 2256 | "dev": true, 2257 | "optional": true 2258 | }, 2259 | "function-bind": { 2260 | "version": "1.1.1", 2261 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 2262 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 2263 | "dev": true 2264 | }, 2265 | "gensync": { 2266 | "version": "1.0.0-beta.2", 2267 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 2268 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", 2269 | "dev": true 2270 | }, 2271 | "globals": { 2272 | "version": "11.12.0", 2273 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 2274 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", 2275 | "dev": true 2276 | }, 2277 | "has": { 2278 | "version": "1.0.3", 2279 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 2280 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 2281 | "dev": true, 2282 | "requires": { 2283 | "function-bind": "^1.1.1" 2284 | } 2285 | }, 2286 | "has-flag": { 2287 | "version": "3.0.0", 2288 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 2289 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 2290 | "dev": true 2291 | }, 2292 | "immer": { 2293 | "version": "9.0.16", 2294 | "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", 2295 | "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==" 2296 | }, 2297 | "is-core-module": { 2298 | "version": "2.9.0", 2299 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", 2300 | "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", 2301 | "dev": true, 2302 | "requires": { 2303 | "has": "^1.0.3" 2304 | } 2305 | }, 2306 | "js-tokens": { 2307 | "version": "4.0.0", 2308 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 2309 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 2310 | }, 2311 | "jsesc": { 2312 | "version": "2.5.2", 2313 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", 2314 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", 2315 | "dev": true 2316 | }, 2317 | "json5": { 2318 | "version": "2.2.1", 2319 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", 2320 | "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", 2321 | "dev": true 2322 | }, 2323 | "loose-envify": { 2324 | "version": "1.4.0", 2325 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 2326 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 2327 | "requires": { 2328 | "js-tokens": "^3.0.0 || ^4.0.0" 2329 | } 2330 | }, 2331 | "ms": { 2332 | "version": "2.1.2", 2333 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2334 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 2335 | "dev": true 2336 | }, 2337 | "nanoid": { 2338 | "version": "3.3.4", 2339 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", 2340 | "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", 2341 | "dev": true 2342 | }, 2343 | "node-releases": { 2344 | "version": "2.0.6", 2345 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", 2346 | "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", 2347 | "dev": true 2348 | }, 2349 | "object-assign": { 2350 | "version": "4.1.1", 2351 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 2352 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" 2353 | }, 2354 | "path-parse": { 2355 | "version": "1.0.7", 2356 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 2357 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 2358 | "dev": true 2359 | }, 2360 | "picocolors": { 2361 | "version": "1.0.0", 2362 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 2363 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 2364 | "dev": true 2365 | }, 2366 | "picomatch": { 2367 | "version": "2.3.1", 2368 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 2369 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 2370 | "dev": true 2371 | }, 2372 | "postcss": { 2373 | "version": "8.4.14", 2374 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", 2375 | "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", 2376 | "dev": true, 2377 | "requires": { 2378 | "nanoid": "^3.3.4", 2379 | "picocolors": "^1.0.0", 2380 | "source-map-js": "^1.0.2" 2381 | } 2382 | }, 2383 | "prop-types": { 2384 | "version": "15.8.1", 2385 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", 2386 | "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", 2387 | "requires": { 2388 | "loose-envify": "^1.4.0", 2389 | "object-assign": "^4.1.1", 2390 | "react-is": "^16.13.1" 2391 | } 2392 | }, 2393 | "react": { 2394 | "version": "18.2.0", 2395 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", 2396 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", 2397 | "requires": { 2398 | "loose-envify": "^1.1.0" 2399 | } 2400 | }, 2401 | "react-device-detect": { 2402 | "version": "2.2.3", 2403 | "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz", 2404 | "integrity": "sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==", 2405 | "requires": { 2406 | "ua-parser-js": "^1.0.33" 2407 | } 2408 | }, 2409 | "react-dom": { 2410 | "version": "18.2.0", 2411 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", 2412 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", 2413 | "requires": { 2414 | "loose-envify": "^1.1.0", 2415 | "scheduler": "^0.23.0" 2416 | } 2417 | }, 2418 | "react-is": { 2419 | "version": "16.13.1", 2420 | "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", 2421 | "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" 2422 | }, 2423 | "react-refresh": { 2424 | "version": "0.13.0", 2425 | "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.13.0.tgz", 2426 | "integrity": "sha512-XP8A9BT0CpRBD+NYLLeIhld/RqG9+gktUjW1FkE+Vm7OCinbG1SshcK5tb9ls4kzvjZr9mOQc7HYgBngEyPAXg==", 2427 | "dev": true 2428 | }, 2429 | "resolve": { 2430 | "version": "1.22.1", 2431 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 2432 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 2433 | "dev": true, 2434 | "requires": { 2435 | "is-core-module": "^2.9.0", 2436 | "path-parse": "^1.0.7", 2437 | "supports-preserve-symlinks-flag": "^1.0.0" 2438 | } 2439 | }, 2440 | "rollup": { 2441 | "version": "2.76.0", 2442 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.76.0.tgz", 2443 | "integrity": "sha512-9jwRIEY1jOzKLj3nsY/yot41r19ITdQrhs+q3ggNWhr9TQgduHqANvPpS32RNpzGklJu3G1AJfvlZLi/6wFgWA==", 2444 | "dev": true, 2445 | "requires": { 2446 | "fsevents": "~2.3.2" 2447 | } 2448 | }, 2449 | "safe-buffer": { 2450 | "version": "5.1.2", 2451 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 2452 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 2453 | "dev": true 2454 | }, 2455 | "scheduler": { 2456 | "version": "0.23.0", 2457 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", 2458 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", 2459 | "requires": { 2460 | "loose-envify": "^1.1.0" 2461 | } 2462 | }, 2463 | "semver": { 2464 | "version": "6.3.0", 2465 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 2466 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 2467 | "dev": true 2468 | }, 2469 | "source-map-js": { 2470 | "version": "1.0.2", 2471 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 2472 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 2473 | "dev": true 2474 | }, 2475 | "supports-color": { 2476 | "version": "5.5.0", 2477 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 2478 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 2479 | "dev": true, 2480 | "requires": { 2481 | "has-flag": "^3.0.0" 2482 | } 2483 | }, 2484 | "supports-preserve-symlinks-flag": { 2485 | "version": "1.0.0", 2486 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 2487 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 2488 | "dev": true 2489 | }, 2490 | "to-fast-properties": { 2491 | "version": "2.0.0", 2492 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 2493 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", 2494 | "dev": true 2495 | }, 2496 | "typescript": { 2497 | "version": "4.7.4", 2498 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", 2499 | "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", 2500 | "dev": true 2501 | }, 2502 | "ua-parser-js": { 2503 | "version": "1.0.35", 2504 | "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", 2505 | "integrity": "sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==" 2506 | }, 2507 | "update-browserslist-db": { 2508 | "version": "1.0.4", 2509 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.4.tgz", 2510 | "integrity": "sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==", 2511 | "dev": true, 2512 | "requires": { 2513 | "escalade": "^3.1.1", 2514 | "picocolors": "^1.0.0" 2515 | } 2516 | }, 2517 | "vite": { 2518 | "version": "2.9.14", 2519 | "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.14.tgz", 2520 | "integrity": "sha512-P/UCjSpSMcE54r4mPak55hWAZPlyfS369svib/gpmz8/01L822lMPOJ/RYW6tLCe1RPvMvOsJ17erf55bKp4Hw==", 2521 | "dev": true, 2522 | "requires": { 2523 | "esbuild": "^0.14.27", 2524 | "fsevents": "~2.3.2", 2525 | "postcss": "^8.4.13", 2526 | "resolve": "^1.22.0", 2527 | "rollup": "^2.59.0" 2528 | } 2529 | } 2530 | } 2531 | } 2532 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-vite", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "tsc && vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "@fortawesome/fontawesome-svg-core": "^6.2.1", 12 | "@fortawesome/free-brands-svg-icons": "^6.2.1", 13 | "@fortawesome/free-solid-svg-icons": "^6.2.1", 14 | "@fortawesome/react-fontawesome": "^0.2.0", 15 | "immer": "^9.0.16", 16 | "react": "^18.0.0", 17 | "react-device-detect": "^2.2.3", 18 | "react-dom": "^18.0.0" 19 | }, 20 | "devDependencies": { 21 | "@types/react": "^18.0.0", 22 | "@types/react-dom": "^18.0.0", 23 | "@vitejs/plugin-react": "^1.3.0", 24 | "typescript": "^4.6.3", 25 | "vite": "^2.9.9" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /public/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonngdev/algorithms-visualizer/23a20d434f9302ecec648511def449d1190de8e0/public/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonngdev/algorithms-visualizer/23a20d434f9302ecec648511def449d1190de8e0/public/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonngdev/algorithms-visualizer/23a20d434f9302ecec648511def449d1190de8e0/public/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /public/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonngdev/algorithms-visualizer/23a20d434f9302ecec648511def449d1190de8e0/public/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonngdev/algorithms-visualizer/23a20d434f9302ecec648511def449d1190de8e0/public/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonngdev/algorithms-visualizer/23a20d434f9302ecec648511def449d1190de8e0/public/favicon/favicon.ico -------------------------------------------------------------------------------- /public/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /public/images/site-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonngdev/algorithms-visualizer/23a20d434f9302ecec648511def449d1190de8e0/public/images/site-screenshot.png -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | display: flex; 3 | flex-direction: column; 4 | align-items: center; 5 | padding: var(--spacing-md); 6 | width: 100%; 7 | row-gap: var(--spacing-md); 8 | } 9 | 10 | .title { 11 | background: var(--gradient-accent); 12 | border-radius: var(--border-radius-lg); 13 | padding: var(--spacing-lg) var(--spacing-md); 14 | width: 100%; 15 | display: flex; 16 | flex-direction: column; 17 | align-items: center; 18 | color: white; 19 | box-shadow: var(--box-shadow); 20 | } 21 | 22 | .title h1 { 23 | font-weight: normal; 24 | font-family: var(--font-family-title); 25 | font-size: var(--font-size-xl); 26 | margin: 0; 27 | } 28 | 29 | .title .desktop { 30 | display: none; 31 | } 32 | 33 | .title .mobile { 34 | margin-top: var(--spacing-sm); 35 | } 36 | 37 | .title .mobile .icon { 38 | margin-left: 0.5rem; 39 | } 40 | 41 | .title .mobile a, .title .mobile a:visited { 42 | color: white; 43 | } 44 | 45 | .main-grid, .actions, .tips { 46 | border-radius: var(--border-radius-lg); 47 | padding: var(--spacing-lg) var(--spacing-md); 48 | width: 100%; 49 | display: flex; 50 | flex-direction: column; 51 | align-items: center; 52 | background-color: white; 53 | box-shadow: var(--box-shadow); 54 | } 55 | 56 | .main-grid h2, .actions h2, .tips h2 { 57 | align-self: flex-start; 58 | margin: 0; 59 | font-size: var(--font-size-lg); 60 | font-weight: bold; 61 | background-image: var(--gradient-accent); 62 | color: transparent; 63 | background-clip: text; 64 | -webkit-background-clip: text; 65 | } 66 | 67 | .main-grid .legends { 68 | display: grid; 69 | grid-template-areas: 70 | "start unvisited shortest" 71 | "end visited wall"; 72 | width: 100%; 73 | row-gap: var(--spacing-sm); 74 | margin-top: var(--spacing-md); 75 | } 76 | 77 | .main-grid .legends .legend-group { 78 | display: flex; 79 | column-gap: 0.5rem; 80 | align-items: center; 81 | } 82 | 83 | .main-grid .legends .legend-group.start { 84 | grid-area: start; 85 | } 86 | 87 | .main-grid .legends .legend-group.end { 88 | grid-area: end; 89 | } 90 | 91 | .main-grid .legends .legend-group { 92 | grid-area: unvisited; 93 | } 94 | 95 | .main-grid .legends .legend-group.visited { 96 | grid-area: visited; 97 | } 98 | 99 | .main-grid .legends .legend-group.on-path { 100 | grid-area: shortest; 101 | } 102 | 103 | .main-grid .legends .legend-group.wall { 104 | grid-area: wall; 105 | } 106 | 107 | .main-grid .legends .legend-group .node { 108 | --node-width: 18px; 109 | } 110 | 111 | .main-grid .legends .legend-group .label { 112 | font-size: 0.75rem; 113 | } 114 | 115 | .main-grid .grid { 116 | --grid-gap: calc((100vw - 4 * var(--spacing-md) - 11 * var(--node-width)) / 10); 117 | grid-area: grid; 118 | justify-self: center; 119 | display: grid; 120 | row-gap: var(--grid-gap); 121 | column-gap: var(--grid-gap); 122 | width: fit-content; 123 | margin-top: var(--spacing-md); 124 | } 125 | 126 | .actions .algorithms { 127 | display: grid; 128 | grid-template-columns: 1fr 1fr; 129 | gap: var(--spacing-sm); 130 | width: 100%; 131 | margin-top: var(--spacing-md); 132 | } 133 | 134 | .actions .cleanup-buttons { 135 | display: grid; 136 | grid-template-columns: 1fr 1fr 1fr; 137 | column-gap: var(--spacing-sm); 138 | width: 100%; 139 | margin-top: var(--spacing-md); 140 | } 141 | 142 | .actions button { 143 | color: var(--color-foreground); 144 | background-color: var(--color-background); 145 | font-weight: bold; 146 | cursor: pointer; 147 | border: none; 148 | transition: background-color ease-in-out 0.1s; 149 | } 150 | 151 | .actions button:is(:hover, :focus-visible) { 152 | background-color: var(--color-background-dark); 153 | } 154 | 155 | .actions .algorithms button { 156 | padding: var(--spacing-md); 157 | border-radius: var(--border-radius-md); 158 | } 159 | 160 | .actions .cleanup-buttons button { 161 | padding: var(--spacing-sm); 162 | border-radius: var(--border-radius-sm); 163 | font-size: var(--font-size-sm); 164 | } 165 | 166 | .tips ul { 167 | margin: 0; 168 | margin-top: var(--spacing-md); 169 | padding-left: 1rem; 170 | align-self: flex-start; 171 | } 172 | 173 | .tips ul li:not(:last-child) { 174 | margin-bottom: var(--spacing-sm); 175 | } 176 | 177 | .tips ul li::marker { 178 | color: var(--color-accent-1); 179 | } 180 | 181 | code { 182 | background-color: var(--color-background); 183 | padding: 0.1rem 0.25rem; 184 | border-radius: 0.25rem; 185 | font-weight: bold; 186 | } 187 | 188 | footer { 189 | width: 100%; 190 | display: flex; 191 | flex-direction: column; 192 | align-items: center; 193 | margin-top: var(--spacing-xl); 194 | font-size: var(--font-size-sm); 195 | } 196 | 197 | footer .icon { 198 | margin-left: 0.2em; 199 | margin-right: 0.2em; 200 | color: var(--color-accent-3); 201 | } 202 | 203 | footer .contacts { 204 | margin: var(--spacing-md) 0; 205 | display: flex; 206 | gap: 0.75rem; 207 | align-items: center; 208 | } 209 | 210 | footer a, footer a:visited { 211 | color: var(--color-foreground); 212 | } 213 | 214 | @media screen and (min-width: 962px) { 215 | .App { 216 | padding: 2rem 4rem 1rem; 217 | display: grid; 218 | grid-template-areas: 219 | "title title" 220 | "grid controls" 221 | "grid tips" 222 | "footer footer"; 223 | grid-template-columns: auto 350px; 224 | grid-template-rows: auto auto 1fr auto; 225 | column-gap: var(--spacing-lg); 226 | } 227 | 228 | .title { 229 | background: transparent; 230 | border-radius: 0; 231 | padding: 0; 232 | width: 100%; 233 | position: relative; 234 | box-shadow: none; 235 | grid-area: title; 236 | margin-bottom: var(--spacing-md); 237 | } 238 | 239 | .title h1 { 240 | background-image: var(--gradient-accent); 241 | background-clip: text; 242 | -webkit-background-clip: text; 243 | color: transparent; 244 | font-size: var(--font-size-xxl) 245 | } 246 | 247 | .title .mobile { 248 | display: none; 249 | } 250 | 251 | .title .desktop { 252 | display: block; 253 | position: absolute; 254 | top: 50%; 255 | right: 0; 256 | transform: translateY(-50%); 257 | } 258 | 259 | .title .desktop a, .title .desktop a:visited { 260 | color: var(--color-foreground); 261 | } 262 | 263 | .main-grid { 264 | grid-area: grid; 265 | align-self: stretch; 266 | } 267 | 268 | .main-grid .legends { 269 | grid-template-areas: "start end unvisited visited shortest wall"; 270 | width: fit-content; 271 | column-gap: var(--spacing-md); 272 | } 273 | 274 | .main-grid .grid { 275 | --grid-gap: 2px; 276 | --node-width: 24px; 277 | } 278 | 279 | .actions { 280 | grid-area: controls; 281 | align-self: start; 282 | } 283 | 284 | .tips { 285 | grid-area: tips; 286 | align-self: stretch; 287 | } 288 | 289 | footer { 290 | grid-area: footer; 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { DragEventHandler, useMemo, useRef, useState } from 'react'; 2 | import produce from 'immer'; 3 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 4 | import { faGithub, faLinkedinIn, faTwitter } from '@fortawesome/free-brands-svg-icons'; 5 | import { faHeart, faGlobe } from '@fortawesome/free-solid-svg-icons'; 6 | import { isMobile } from 'react-device-detect'; 7 | 8 | import Node, { NodeType } from './components/Node'; 9 | import { calculateDefaultNodePositions, calculateGridDimension } from './utils/dimension'; 10 | import { Node as NodeDS, NodeData as NodeDSData } from './data-structures/Node'; 11 | import { PathfindingAlgorithm } from './algorithms/types'; 12 | import DFS from './algorithms/DFS'; 13 | import BFS from './algorithms/BFS'; 14 | import Dijkstra from './algorithms/Dijkstra'; 15 | import AStar from './algorithms/AStar'; 16 | import './App.css'; 17 | 18 | type NodeState = { 19 | isVisited: boolean; 20 | isOnPath: boolean; 21 | isWall: boolean; 22 | }; 23 | 24 | type NodeData = { 25 | row: number; 26 | col: number; 27 | }; 28 | 29 | export type DragState = { 30 | isActive: boolean; 31 | nodeType: NodeType | null; 32 | row: number; 33 | col: number; 34 | }; 35 | 36 | const gridDimension = calculateGridDimension(); 37 | const NUM_ROWS = gridDimension.rows; 38 | const NUM_COLS = gridDimension.cols; 39 | const defaultPositions = calculateDefaultNodePositions(gridDimension); 40 | const DEFAULT_START_NODE_POS = defaultPositions.start; 41 | const DEFAULT_END_NODE_POS = defaultPositions.end; 42 | 43 | function App() { 44 | const [startNodePos, setStartNodePos] = useState(DEFAULT_START_NODE_POS); 45 | const [endNodePos, setEndNodePos] = useState(DEFAULT_END_NODE_POS); 46 | const initialNodeStates = useMemo(() => { 47 | const states: NodeState[][] = []; 48 | for (let i = 0; i < NUM_ROWS; i++) { 49 | const row: NodeState[] = []; 50 | for (let j = 0; j < NUM_COLS; j++) { 51 | row.push({ isVisited: false, isOnPath: false, isWall: false }); 52 | } 53 | states.push(row); 54 | } 55 | return states; 56 | }, [NUM_ROWS, NUM_COLS]); 57 | const [nodeStates, setNodeStates] = useState(initialNodeStates); 58 | const timeoutRef = useRef([]); 59 | const [dragState, setDragState] = useState({ 60 | isActive: false, 61 | nodeType: null, 62 | row: 0, 63 | col: 0, 64 | }); 65 | const [isCreatingWall, setIsCreatingWall] = useState(false); 66 | 67 | //-------------Helpers-------------// 68 | 69 | const clearVisualizedPath = () => { 70 | setNodeStates( 71 | produce((draft) => { 72 | for (let row of draft) { 73 | for (let nodeState of row) { 74 | nodeState.isVisited = false; 75 | nodeState.isOnPath = false; 76 | } 77 | } 78 | }), 79 | ); 80 | timeoutRef.current.forEach(clearTimeout); 81 | timeoutRef.current = []; 82 | }; 83 | 84 | const resetNodeStates = () => { 85 | setNodeStates(initialNodeStates); 86 | timeoutRef.current.forEach(clearTimeout); 87 | timeoutRef.current = []; 88 | }; 89 | 90 | const resetGrid = () => { 91 | setStartNodePos(DEFAULT_START_NODE_POS); 92 | setEndNodePos(DEFAULT_END_NODE_POS); 93 | setNodeStates(initialNodeStates); 94 | timeoutRef.current.forEach(clearTimeout); 95 | timeoutRef.current = []; 96 | }; 97 | 98 | //-------------Visualizing pathfinding algorithm-------------// 99 | 100 | const getWallPositions = () => { 101 | const wallPositions = []; 102 | for (let i = 0; i < nodeStates.length; i++) { 103 | for (let j = 0; j < nodeStates[i].length; j++) { 104 | if (nodeStates[i][j].isWall) { 105 | wallPositions.push({ row: i, col: j }); 106 | } 107 | } 108 | } 109 | return wallPositions; 110 | }; 111 | 112 | const animateAlgorithm = ( 113 | visitedNodes: NodeDS[], 114 | shortestPath: NodeDS[], 115 | ) => { 116 | for (let i = 0; i < visitedNodes.length; i++) { 117 | const timeout = setTimeout(() => { 118 | const { 119 | data: { row, col }, 120 | } = visitedNodes[i]; 121 | setNodeStates( 122 | produce((draft) => { 123 | draft[row][col].isVisited = true; 124 | }), 125 | ); 126 | }, i * 5); 127 | timeoutRef.current.push(timeout); 128 | } 129 | 130 | for (let i = 0; i < shortestPath.length; i++) { 131 | const timeout = setTimeout(() => { 132 | const { 133 | data: { row, col }, 134 | } = shortestPath[i]; 135 | setNodeStates( 136 | produce((draft) => { 137 | draft[row][col].isOnPath = true; 138 | }), 139 | ); 140 | }, (visitedNodes.length + i * 4) * 5); // Slow down shortest path animation by 4 times 141 | timeoutRef.current.push(timeout); 142 | } 143 | }; 144 | 145 | const visualizeAlgorithm = (algorithm: PathfindingAlgorithm) => { 146 | clearVisualizedPath(); 147 | 148 | const { grid, startNode, endNode } = algorithm.createGridData( 149 | NUM_ROWS, 150 | NUM_COLS, 151 | startNodePos, 152 | endNodePos, 153 | getWallPositions(), 154 | ); 155 | if (!startNode || !endNode) { 156 | return; 157 | } 158 | 159 | const { visitedNodes, shortestPath } = algorithm.performAlgorithm( 160 | grid.flat(), 161 | startNode, 162 | endNode, 163 | ); 164 | animateAlgorithm(visitedNodes, shortestPath); 165 | } 166 | 167 | //-------------Moving start/end nodes-------------// 168 | 169 | const handleDragStart = (nodeType: NodeType, row: number, col: number) => { 170 | clearVisualizedPath(); 171 | setDragState({ isActive: true, nodeType, row, col }); 172 | }; 173 | 174 | const handleDragEnter = (row: number, col: number) => { 175 | setDragState({ ...dragState, row, col }); 176 | }; 177 | 178 | const handleDragOver: DragEventHandler = (event) => { 179 | event.preventDefault(); 180 | event.dataTransfer.dropEffect = 'move'; 181 | }; 182 | 183 | const handleDrop: DragEventHandler = () => { 184 | const { nodeType, row, col } = dragState; 185 | if (nodeType === NodeType.START) { 186 | setStartNodePos({ row: row, col: col }); 187 | } else if (nodeType === NodeType.END) { 188 | setEndNodePos({ row: row, col: col }); 189 | } 190 | setDragState({ isActive: false, nodeType: null, row: 0, col: 0 }); 191 | }; 192 | 193 | //-------------Creating walls-------------// 194 | 195 | const handleNodeClick = (row: number, col: number) => { 196 | clearVisualizedPath(); 197 | setNodeStates( 198 | produce((draft) => { 199 | draft[row][col].isWall = !draft[row][col].isWall; 200 | }), 201 | ); 202 | }; 203 | 204 | const handleNodeMouseDown = (row: number, col: number) => { 205 | clearVisualizedPath(); 206 | setIsCreatingWall(true); 207 | setNodeStates( 208 | produce((draft) => { 209 | draft[row][col].isWall = true; 210 | }), 211 | ); 212 | }; 213 | 214 | const handleNodeMouseEnter = (row: number, col: number) => { 215 | if (isCreatingWall) { 216 | setNodeStates( 217 | produce((draft) => { 218 | draft[row][col].isWall = true; 219 | }), 220 | ); 221 | } 222 | }; 223 | 224 | const handleNodeMouseUp = () => { 225 | setIsCreatingWall(false); 226 | }; 227 | 228 | return ( 229 |
230 |
231 |

Pathfinding Algorithms Visualizer

232 |
233 | Check out on GitHub 234 | 235 |
236 |
237 | 238 | 239 | 240 |
241 |
242 | 243 |
244 |

Grid

245 |
246 |
247 |
248 | Start 249 |
250 |
251 |
252 | End 253 |
254 |
255 |
256 | Unvisited 257 |
258 |
259 |
260 | Visited 261 |
262 |
263 |
264 | Shortest 265 |
266 |
267 |
268 | Wall 269 |
270 |
271 | 272 |
281 | {nodeStates.map((row, rowIndex) => 282 | row.map((nodeState, colIndex) => { 283 | let type: NodeType; 284 | if ( 285 | rowIndex === startNodePos.row && 286 | colIndex === startNodePos.col 287 | ) { 288 | type = NodeType.START; 289 | } else if ( 290 | rowIndex === endNodePos.row && 291 | colIndex === endNodePos.col 292 | ) { 293 | type = NodeType.END; 294 | } else { 295 | type = NodeType.MIDDLE; 296 | } 297 | const { isVisited, isOnPath, isWall } = nodeState; 298 | 299 | return ( 300 | 316 | ); 317 | }), 318 | )} 319 |
320 |
321 | 322 |
323 |

Controls

324 | 325 |
326 | 333 | 340 | 347 | 354 |
355 | 356 |
357 | 364 | 371 | 374 |
375 |
376 | 377 |
378 |

Tips

379 | {isMobile ? ( 380 |
    381 |
  • 382 |
    383 | View this site on desktop to see extra features. 384 |
    385 |
  • 386 |
  • 387 |
    388 | Tap on a white node to toggle a wall. 389 |
    390 |
  • 391 |
392 | ) : ( 393 |
    394 |
  • 395 |
    396 | Try dragging the start/end nodes to new positions. 397 |
    398 |
  • 399 |
  • 400 |
    401 | Click on a white node and drag to create walls quickly. 402 |
    403 |
  • 404 |
  • 405 |
    406 | Hold ctrl/cmd and click on a white node to toggle a wall. 407 |
    408 |
  • 409 |
410 | )} 411 |
412 | 413 | 430 |
431 | ); 432 | } 433 | 434 | export default App; 435 | -------------------------------------------------------------------------------- /src/algorithms/AStar.ts: -------------------------------------------------------------------------------- 1 | import { Node, NodeData } from '../data-structures/Node'; 2 | import { CreateGridDataFn, PathfindingAlgorithm, PerformAlgorithmFn } from './types'; 3 | 4 | interface AStarNodeData extends NodeData { 5 | fScore: number; // Total cost 6 | gScore: number; // Cost to traverse from start node to this node 7 | hScore: number; // Heuristic (estimated cost from this node to end node) 8 | } 9 | 10 | export const createGridData: CreateGridDataFn = ( 11 | rows, 12 | cols, 13 | startNodePosition, 14 | endNodePosition, 15 | wallPositions, 16 | ) => { 17 | let grid: Node[][] = []; 18 | let startNode: Node | null = null; 19 | let endNode: Node | null = null; 20 | 21 | for (let i = 0; i < rows; i++) { 22 | const row: Node[] = []; 23 | for (let j = 0; j < cols; j++) { 24 | const node = new Node({ 25 | row: i, 26 | col: j, 27 | fScore: Infinity, 28 | gScore: Infinity, 29 | hScore: Infinity, 30 | }); 31 | if (j > 0) { 32 | const leftNode = row[j - 1]; 33 | node.neighbors.push(leftNode); 34 | leftNode.neighbors.push(node); 35 | } 36 | if (i > 0) { 37 | const topNode = grid[i - 1][j]; 38 | node.neighbors.push(topNode); 39 | topNode.neighbors.push(node); 40 | } 41 | 42 | row.push(node); 43 | 44 | if (i === startNodePosition.row && j === startNodePosition.col) { 45 | startNode = node; 46 | } else if (i === endNodePosition.row && j === endNodePosition.col) { 47 | endNode = node; 48 | } 49 | } 50 | grid.push(row); 51 | } 52 | 53 | for (let wallPosition of wallPositions) { 54 | const { row, col } = wallPosition; 55 | grid[row][col].isWall = true; 56 | } 57 | 58 | return { grid, startNode, endNode }; 59 | } 60 | 61 | export function calculateHeuristic( 62 | node: Node, 63 | endNode: Node, 64 | ): number { 65 | // For now, don't allow a node to move diagonally 66 | return ( 67 | Math.abs(node.data.row - endNode.data.row) + 68 | Math.abs(node.data.col - endNode.data.col) 69 | ); 70 | } 71 | 72 | /** 73 | * Pseudo code: https://en.wikipedia.org/wiki/A*_search_algorithm 74 | */ 75 | export const performAlgorithm: PerformAlgorithmFn = ( 76 | grid, 77 | startNode, 78 | endNode, 79 | ) => { 80 | const shortestPath: Node[] = []; 81 | const visitedNodes: Node[] = []; 82 | 83 | for (let node of grid) { 84 | node.data.gScore = node === startNode ? 0 : Infinity; 85 | node.data.hScore = calculateHeuristic(node, endNode); 86 | node.data.fScore = node.data.gScore + node.data.hScore; 87 | node.previousNode = null; 88 | } 89 | 90 | const openSet: Node[] = [startNode]; 91 | 92 | while (openSet.length > 0) { 93 | // debugger; 94 | openSet.sort((node1, node2) => node1.data.fScore - node2.data.fScore); 95 | const currentNode = openSet.shift(); 96 | if (!currentNode) { 97 | break; 98 | } 99 | if (currentNode.isWall) { 100 | continue; 101 | } 102 | 103 | visitedNodes.push(currentNode); 104 | if (currentNode === endNode) { 105 | break; 106 | } 107 | for (let neighbor of currentNode.neighbors) { 108 | let tentativeGScore = currentNode.data.gScore + 1; 109 | // Find a new best path to a neighbor, record it 110 | if (tentativeGScore < neighbor.data.gScore) { 111 | neighbor.previousNode = currentNode; 112 | neighbor.data.gScore = tentativeGScore; 113 | neighbor.data.fScore = tentativeGScore + neighbor.data.hScore; 114 | if (!openSet.includes(neighbor)) { 115 | openSet.push(neighbor); 116 | } 117 | } 118 | } 119 | } 120 | 121 | let shortestPathRunner = endNode; 122 | while (shortestPathRunner !== startNode) { 123 | shortestPath.unshift(shortestPathRunner); 124 | if (shortestPathRunner.previousNode) { 125 | shortestPathRunner = shortestPathRunner.previousNode; 126 | } else { 127 | // Can't backtrace to originNode, there is no shortest path 128 | break; 129 | } 130 | } 131 | 132 | return { shortestPath, visitedNodes }; 133 | } 134 | 135 | const AStar: PathfindingAlgorithm = { 136 | createGridData, 137 | performAlgorithm, 138 | }; 139 | 140 | export default AStar; 141 | -------------------------------------------------------------------------------- /src/algorithms/BFS.ts: -------------------------------------------------------------------------------- 1 | import { Node, NodeData } from '../data-structures/Node'; 2 | import { CreateGridDataFn, PathfindingAlgorithm, PerformAlgorithmFn } from './types'; 3 | 4 | interface BFSNodeData extends NodeData { 5 | isVisited: boolean; 6 | } 7 | 8 | export const createGridData: CreateGridDataFn = ( 9 | rows, 10 | cols, 11 | startNodePosition, 12 | endNodePosition, 13 | wallPositions, 14 | ) => { 15 | let grid: Node[][] = []; 16 | let startNode: Node | null = null; 17 | let endNode: Node | null = null; 18 | 19 | for (let i = 0; i < rows; i++) { 20 | const row: Node[] = []; 21 | for (let j = 0; j < cols; j++) { 22 | const node = new Node({ 23 | row: i, 24 | col: j, 25 | isVisited: false, 26 | }); 27 | if (j > 0) { 28 | const leftNode = row[j - 1]; 29 | node.neighbors.push(leftNode); 30 | leftNode.neighbors.push(node); 31 | } 32 | if (i > 0) { 33 | const topNode = grid[i - 1][j]; 34 | node.neighbors.push(topNode); 35 | topNode.neighbors.push(node); 36 | } 37 | 38 | row.push(node); 39 | 40 | if (i === startNodePosition.row && j === startNodePosition.col) { 41 | startNode = node; 42 | } else if (i === endNodePosition.row && j === endNodePosition.col) { 43 | endNode = node; 44 | } 45 | } 46 | grid.push(row); 47 | } 48 | 49 | for (let wallPosition of wallPositions) { 50 | const { row, col } = wallPosition; 51 | grid[row][col].isWall = true; 52 | } 53 | 54 | return { grid, startNode, endNode }; 55 | }; 56 | 57 | export const performAlgorithm: PerformAlgorithmFn = ( 58 | grid, 59 | originNode, 60 | destinationNode, 61 | ) => { 62 | const shortestPath: Node[] = []; 63 | const visitedNodes: Node[] = []; 64 | 65 | for (let node of grid) { 66 | node.data.isVisited = false; 67 | node.previousNode = null; 68 | } 69 | 70 | const queue: Node[] = [originNode]; 71 | let nodeRunner: Node; 72 | 73 | while (queue.length > 0) { 74 | nodeRunner = queue.shift()!; 75 | 76 | // Still need to check here even though at the time of enqueuing 77 | // to the queue, we only enqueue unvisited nodes, because by the 78 | // time we get back to it, it can be already visited from a 79 | // different node. 80 | if (nodeRunner.data.isVisited) { 81 | continue; 82 | } 83 | 84 | nodeRunner.data.isVisited = true; 85 | visitedNodes.push(nodeRunner); 86 | 87 | if (nodeRunner === destinationNode) { 88 | break; 89 | } 90 | 91 | const unvisitedNeighbors = nodeRunner.neighbors.filter( 92 | (node) => !node.data.isVisited && !node.isWall 93 | ); 94 | for (let neighbor of unvisitedNeighbors) { 95 | neighbor.previousNode = nodeRunner; 96 | } 97 | queue.push(...unvisitedNeighbors); 98 | } 99 | 100 | let shortestPathRunner = destinationNode; 101 | while (shortestPathRunner !== originNode) { 102 | shortestPath.unshift(shortestPathRunner); 103 | if (shortestPathRunner.previousNode) { 104 | shortestPathRunner = shortestPathRunner.previousNode; 105 | } else { 106 | // Can't backtrace to originNode, there is no shortest path 107 | break; 108 | } 109 | } 110 | 111 | // console.log(visitedNodes); 112 | return { shortestPath, visitedNodes }; 113 | }; 114 | 115 | const BFS: PathfindingAlgorithm = { 116 | createGridData, 117 | performAlgorithm, 118 | }; 119 | 120 | export default BFS; 121 | -------------------------------------------------------------------------------- /src/algorithms/DFS.ts: -------------------------------------------------------------------------------- 1 | import { Node, NodeData } from '../data-structures/Node'; 2 | import { CreateGridDataFn, PathfindingAlgorithm, PerformAlgorithmFn } from './types'; 3 | 4 | interface DFSNodeData extends NodeData { 5 | isVisited: boolean; 6 | } 7 | 8 | export const createGridData: CreateGridDataFn = ( 9 | rows, 10 | cols, 11 | startNodePosition, 12 | endNodePosition, 13 | wallPositions, 14 | ) => { 15 | let grid: Node[][] = []; 16 | let startNode: Node | null = null; 17 | let endNode: Node | null = null; 18 | 19 | for (let i = 0; i < rows; i++) { 20 | const row: Node[] = []; 21 | for (let j = 0; j < cols; j++) { 22 | const node = new Node({ 23 | row: i, 24 | col: j, 25 | isVisited: false, 26 | }); 27 | if (j > 0) { 28 | const leftNode = row[j - 1]; 29 | node.neighbors.push(leftNode); 30 | leftNode.neighbors.push(node); 31 | } 32 | if (i > 0) { 33 | const topNode = grid[i - 1][j]; 34 | node.neighbors.push(topNode); 35 | topNode.neighbors.push(node); 36 | } 37 | 38 | row.push(node); 39 | 40 | if (i === startNodePosition.row && j === startNodePosition.col) { 41 | startNode = node; 42 | } else if (i === endNodePosition.row && j === endNodePosition.col) { 43 | endNode = node; 44 | } 45 | } 46 | grid.push(row); 47 | } 48 | 49 | for (let wallPosition of wallPositions) { 50 | const { row, col } = wallPosition; 51 | grid[row][col].isWall = true; 52 | } 53 | 54 | return { grid, startNode, endNode }; 55 | }; 56 | 57 | export const performAlgorithm: PerformAlgorithmFn = ( 58 | grid, 59 | originNode, 60 | destinationNode, 61 | ) => { 62 | const shortestPath: Node[] = []; 63 | const visitedNodes: Node[] = []; 64 | 65 | for (let node of grid) { 66 | node.data.isVisited = false; 67 | node.previousNode = null; 68 | } 69 | 70 | const stack: Node[] = [originNode]; 71 | let nodeRunner: Node; 72 | 73 | while (stack.length > 0) { 74 | nodeRunner = stack.pop()!; 75 | 76 | // Still need to check here even though at the time of pushing 77 | // to the stack, we only push unvisited nodes, because by the 78 | // time we get back to it, it can be already visited from a 79 | // different node. 80 | if (nodeRunner.data.isVisited) { 81 | continue; 82 | } 83 | 84 | nodeRunner.data.isVisited = true; 85 | visitedNodes.push(nodeRunner); 86 | 87 | if (nodeRunner === destinationNode) { 88 | break; 89 | } 90 | 91 | const unvisitedNeighbors = nodeRunner.neighbors.filter( 92 | (node) => !node.data.isVisited && !node.isWall 93 | ); 94 | for (let neighbor of unvisitedNeighbors) { 95 | neighbor.previousNode = nodeRunner; 96 | } 97 | stack.push(...unvisitedNeighbors); 98 | } 99 | 100 | let shortestPathRunner = destinationNode; 101 | while (shortestPathRunner !== originNode) { 102 | shortestPath.unshift(shortestPathRunner); 103 | if (shortestPathRunner.previousNode) { 104 | shortestPathRunner = shortestPathRunner.previousNode; 105 | } else { 106 | // Can't backtrace to originNode, there is no shortest path 107 | break; 108 | } 109 | } 110 | 111 | // console.log(visitedNodes); 112 | return { shortestPath, visitedNodes }; 113 | }; 114 | 115 | const DFS: PathfindingAlgorithm = { 116 | createGridData, 117 | performAlgorithm, 118 | }; 119 | 120 | export default DFS; 121 | -------------------------------------------------------------------------------- /src/algorithms/Dijkstra.ts: -------------------------------------------------------------------------------- 1 | import { Node, NodeData } from '../data-structures/Node'; 2 | import { CreateGridDataFn, PathfindingAlgorithm, PerformAlgorithmFn } from './types'; 3 | 4 | interface DijkstraNodeData extends NodeData { 5 | distance: number; 6 | isVisited: boolean; 7 | } 8 | 9 | export const createGridData: CreateGridDataFn = ( 10 | rows, 11 | cols, 12 | startNodePosition, 13 | endNodePosition, 14 | wallPositions, 15 | ) => { 16 | let grid: Node[][] = []; 17 | let startNode: Node | null = null; 18 | let endNode: Node | null = null; 19 | 20 | for (let i = 0; i < rows; i++) { 21 | const row: Node[] = []; 22 | for (let j = 0; j < cols; j++) { 23 | const node = new Node({ 24 | row: i, 25 | col: j, 26 | distance: Infinity, 27 | isVisited: false, 28 | }); 29 | if (j > 0) { 30 | const leftNode = row[j - 1]; 31 | node.neighbors.push(leftNode); 32 | leftNode.neighbors.push(node); 33 | } 34 | if (i > 0) { 35 | const topNode = grid[i - 1][j]; 36 | node.neighbors.push(topNode); 37 | topNode.neighbors.push(node); 38 | } 39 | 40 | row.push(node); 41 | 42 | if (i === startNodePosition.row && j === startNodePosition.col) { 43 | startNode = node; 44 | } else if (i === endNodePosition.row && j === endNodePosition.col) { 45 | endNode = node; 46 | } 47 | } 48 | grid.push(row); 49 | } 50 | 51 | for (let wallPosition of wallPositions) { 52 | const { row , col } = wallPosition; 53 | grid[row][col].isWall = true; 54 | } 55 | 56 | return { grid, startNode, endNode }; 57 | } 58 | 59 | export const performAlgorithm: PerformAlgorithmFn = ( 60 | grid, 61 | originNode, 62 | destinationNode, 63 | ) => { 64 | const shortestPath: Node[] = []; 65 | const visitedNodes: Node[] = []; 66 | 67 | for (let node of grid) { 68 | if (node === originNode) { 69 | node.data.distance = 0; 70 | } else if (node.isNeighbor(originNode)) { 71 | node.data.distance = 1; 72 | } else { 73 | node.data.distance = Infinity; 74 | } 75 | node.data.isVisited = false; 76 | node.previousNode = null; 77 | } 78 | 79 | const unvisitedNodes = grid.slice(); 80 | 81 | while (unvisitedNodes.length > 0) { 82 | unvisitedNodes.sort( 83 | (node1, node2) => node1.data.distance - node2.data.distance, 84 | ); 85 | const closestNode = unvisitedNodes.shift(); 86 | // If the closest node is infinitely far away, 87 | // it is no not connected to the current grid (graph) 88 | // and we should stop 89 | if (!closestNode || closestNode.data.distance === Infinity) { 90 | break; 91 | } 92 | if (closestNode.isWall) { 93 | continue; 94 | } 95 | 96 | closestNode.data.isVisited = true; 97 | visitedNodes.push(closestNode); 98 | if (closestNode === destinationNode) { 99 | break; 100 | } 101 | 102 | const unvisitedNeighbors = closestNode.neighbors.filter( 103 | (node) => !node.data.isVisited, 104 | ); 105 | for (let neighbor of unvisitedNeighbors) { 106 | neighbor.data.distance = closestNode.data.distance + 1; 107 | neighbor.previousNode = closestNode; 108 | } 109 | } 110 | 111 | let shortestPathRunner = destinationNode; 112 | while (shortestPathRunner !== originNode) { 113 | shortestPath.unshift(shortestPathRunner); 114 | if (shortestPathRunner.previousNode) { 115 | shortestPathRunner = shortestPathRunner.previousNode; 116 | } else { 117 | // Can't backtrace to originNode, there is no shortest path 118 | break; 119 | } 120 | } 121 | 122 | return { shortestPath, visitedNodes }; 123 | } 124 | 125 | const Dijkstra: PathfindingAlgorithm = { 126 | createGridData, 127 | performAlgorithm, 128 | }; 129 | 130 | export default Dijkstra; 131 | -------------------------------------------------------------------------------- /src/algorithms/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["ESNext", "DOM"], 5 | "strict": true, 6 | }, 7 | "include": ["**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /src/algorithms/types.ts: -------------------------------------------------------------------------------- 1 | import { Node, NodeData } from "../data-structures/Node"; 2 | 3 | export interface NodePosition { 4 | row: number; 5 | col: number; 6 | } 7 | 8 | export interface GridData { 9 | grid: Node[][], 10 | startNode: Node | null, 11 | endNode: Node | null, 12 | } 13 | 14 | export interface PathfindingResult { 15 | shortestPath: Node[]; 16 | visitedNodes: Node[]; 17 | } 18 | 19 | export type CreateGridDataFn = ( 20 | rows: number, 21 | cols: number, 22 | startNodePosition: NodePosition, 23 | endNodePosition: NodePosition, 24 | wallPositions: NodePosition[], 25 | ) => GridData; 26 | 27 | export type PerformAlgorithmFn = ( 28 | grid: Node[], 29 | startNode: Node, 30 | endNode: Node, 31 | ) => PathfindingResult 32 | 33 | export interface PathfindingAlgorithm { 34 | createGridData: CreateGridDataFn, 35 | performAlgorithm: PerformAlgorithmFn, 36 | } 37 | -------------------------------------------------------------------------------- /src/components/Node.css: -------------------------------------------------------------------------------- 1 | .node { 2 | border: solid 1px black; 3 | width: var(--node-width); 4 | height: var(--node-width); 5 | } 6 | 7 | .node.start { 8 | background-color: #027DFC; 9 | } 10 | 11 | .node.end { 12 | background-color: #00E379; 13 | } 14 | 15 | .node.visited { 16 | background-color: #ffe88e; 17 | } 18 | 19 | .node.on-path { 20 | background-color: #f8bb37; 21 | } 22 | 23 | .node.wall { 24 | background-color: black; 25 | } 26 | 27 | .node.under-drag-start { 28 | background-color: #67b3ff; 29 | } 30 | 31 | .node.under-drag-end { 32 | background-color: #6ff5b6; 33 | } 34 | 35 | .node[draggable="true"] { 36 | cursor: grab; 37 | } 38 | 39 | .node[draggable="true"]:active { 40 | cursor: grabbing; 41 | } 42 | -------------------------------------------------------------------------------- /src/components/Node.tsx: -------------------------------------------------------------------------------- 1 | import { MouseEvent, useEffect, useState } from 'react'; 2 | import { DragState } from '../App'; 3 | import './Node.css'; 4 | 5 | export enum NodeType { 6 | START, 7 | END, 8 | MIDDLE, 9 | } 10 | 11 | type NodeProps = { 12 | row: number; 13 | col: number; 14 | type: NodeType; 15 | isVisited: boolean; 16 | isOnPath: boolean; 17 | isWall: boolean; 18 | dragState: DragState; 19 | onDragStart: (nodeType: NodeType, row: number, col: number) => void; 20 | onDragEnter: (row: number, col: number) => void; 21 | onClick: (row: number, col: number) => void; 22 | onMouseDown: (row: number, col: number) => void; 23 | onMouseEnter: (row: number, col: number) => void; 24 | onMouseUp: () => void; 25 | }; 26 | 27 | export default function Node({ 28 | row, 29 | col, 30 | type, 31 | isOnPath, 32 | isVisited, 33 | isWall, 34 | dragState, 35 | onDragStart, 36 | onDragEnter, 37 | onClick, 38 | onMouseDown, 39 | onMouseEnter, 40 | onMouseUp, 41 | }: NodeProps) { 42 | const [isUnderDrag, setIsUnderDrag] = useState(false); 43 | 44 | let className = 'node'; 45 | if (type === NodeType.START) { 46 | className += ' start'; 47 | } else if (type === NodeType.END) { 48 | className += ' end'; 49 | } else if (isOnPath) { 50 | className += ' on-path'; 51 | } else if (isVisited) { 52 | className += ' visited'; 53 | } else if (isWall) { 54 | className += ' wall'; 55 | } else if (isUnderDrag) { 56 | if (dragState.nodeType === NodeType.START) { 57 | className += ' under-drag-start'; 58 | } else if (dragState.nodeType === NodeType.END) { 59 | className += ' under-drag-end'; 60 | } 61 | } 62 | 63 | //-------------Moving start/end nodes-------------// 64 | 65 | const handleDragStart = () => { 66 | onDragStart(type, row, col); 67 | }; 68 | 69 | const handleDragEnter = () => { 70 | if (!isWall) { 71 | onDragEnter(row, col); 72 | setIsUnderDrag(true); 73 | } 74 | }; 75 | 76 | const handleDragLeave = () => { 77 | setIsUnderDrag(false); 78 | }; 79 | 80 | //-------------Creating walls-------------// 81 | 82 | // Click a node to toggle a wall 83 | const handleClick = (event: MouseEvent) => { 84 | if (type === NodeType.MIDDLE && event.metaKey) { 85 | onClick(row, col); 86 | } 87 | }; 88 | 89 | // Mouse down and drag to create walls quickly 90 | const handleMouseDown = (event: MouseEvent) => { 91 | if (type === NodeType.MIDDLE && !event.metaKey) { 92 | onMouseDown(row, col); 93 | } 94 | }; 95 | 96 | const handleMouseEnter = (event: MouseEvent) => { 97 | if (type === NodeType.MIDDLE && !event.metaKey) { 98 | onMouseEnter(row, col); 99 | } 100 | }; 101 | 102 | const handleMouseUp = (event: MouseEvent) => { 103 | if (!event.metaKey) { 104 | onMouseUp(); 105 | } 106 | }; 107 | 108 | // Sometimes onDragLeave is not called, resulting in false nodes 109 | // being highlighted. 110 | useEffect(() => { 111 | if (!dragState.isActive) { 112 | setIsUnderDrag(false); 113 | } 114 | }, [dragState.isActive]); 115 | 116 | return ( 117 |
128 | ); 129 | } 130 | -------------------------------------------------------------------------------- /src/data-structures/Node.ts: -------------------------------------------------------------------------------- 1 | export interface NodeData { 2 | row: number; 3 | col: number; 4 | } 5 | 6 | export class Node { 7 | public isWall: boolean = false; 8 | public previousNode: Node | null = null; 9 | public neighbors: Node[] = []; 10 | 11 | constructor( 12 | public data: T 13 | ) {} 14 | 15 | isNeighbor(node: Node): boolean { 16 | return this.neighbors.includes(node); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/data-structures/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "lib": ["ESNext", "DOM"], 5 | "strict": true, 6 | }, 7 | "include": ["**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&family=Righteous&display=swap'); 2 | 3 | :root { 4 | --color-accent-1: #027dfc; 5 | --color-accent-2: #00e379; 6 | --color-accent-3: #f43f5e; 7 | --color-foreground: #000000; 8 | --color-background: #edf2f7; 9 | --color-background-dark: #e0e5ea; 10 | 11 | --font-size-xxl: 30px; 12 | --font-size-xl: 20px; 13 | --font-size-lg: 18px; 14 | --font-size-md: 14px; 15 | --font-size-sm: 11px; 16 | 17 | --font-family-title: 'Righteous', serif; 18 | --font-family-body: 'Inter', sans-serif; 19 | 20 | --spacing-xl: 2rem; 21 | --spacing-lg: 1.5rem; 22 | --spacing-md: 1rem; 23 | --spacing-sm: 0.75rem; 24 | 25 | --border-radius-lg: 16px; 26 | --border-radius-md: 8px; 27 | --border-radius-sm: 6px; 28 | 29 | --box-shadow: 0px 25px 50px -12px rgba(0, 0, 0, 0.1); 30 | 31 | --gradient-accent: linear-gradient( 32 | to top right, 33 | var(--color-accent-1), 34 | var(--color-accent-2) 35 | ); 36 | 37 | --node-width: 28px; 38 | } 39 | 40 | * { 41 | box-sizing: border-box; 42 | } 43 | 44 | body { 45 | margin: 0; 46 | font-family: var(--font-family-body); 47 | font-size: var(--font-size-md); 48 | background-color: var(--color-background); 49 | -webkit-font-smoothing: antialiased; 50 | -moz-osx-font-smoothing: grayscale; 51 | } 52 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /src/utils/dimension.ts: -------------------------------------------------------------------------------- 1 | interface GridDimension { 2 | rows: number; 3 | cols: number; 4 | } 5 | 6 | interface NodePosition { 7 | row: number; 8 | col: number; 9 | } 10 | 11 | interface DefaultPositions { 12 | start: NodePosition; 13 | end: NodePosition; 14 | } 15 | 16 | export function calculateGridDimension(): GridDimension { 17 | let rows: number; 18 | let cols: number; 19 | 20 | if (window.innerWidth < 962) { 21 | rows = 9; 22 | cols = 11; 23 | } else { 24 | rows = 15; 25 | cols = 30; 26 | } 27 | 28 | return { rows, cols }; 29 | } 30 | 31 | export function calculateDefaultNodePositions( 32 | gridDimension: GridDimension, 33 | ): DefaultPositions { 34 | const row = Math.floor(gridDimension.rows / 2); 35 | const startCol = Math.floor(gridDimension.cols / 3) - 1; 36 | const endCol = gridDimension.cols - 1 - startCol; 37 | 38 | return { 39 | start: { row, col: startCol }, 40 | end: { row, col: endCol }, 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "esnext", 5 | "moduleResolution": "node" 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()] 7 | }) 8 | --------------------------------------------------------------------------------