diff --git a/nise-backend/src/main/kotlin/com/nisemoe/nise/rss/RssService.kt b/nise-backend/src/main/kotlin/com/nisemoe/nise/rss/RssService.kt index efe95ef..4d75684 100644 --- a/nise-backend/src/main/kotlin/com/nisemoe/nise/rss/RssService.kt +++ b/nise-backend/src/main/kotlin/com/nisemoe/nise/rss/RssService.kt @@ -13,8 +13,7 @@ import java.util.* @Service class RssService( - private val dslContext: DSLContext, - private val scoreService: ScoreService + private val dslContext: DSLContext ) { fun generateFeed(): RssFeed { diff --git a/nise-frontend/Build.sh b/nise-frontend/Build.sh index c5b140d..25d3264 100755 --- a/nise-frontend/Build.sh +++ b/nise-frontend/Build.sh @@ -5,12 +5,6 @@ IMAGE_NAME="nise-frontend" IMAGE_REGISTRY="git.gengo.tech/nuff" IMAGE_VERSION="latest" -# Check if there are uncommitted changes -if [[ -n $(git status --porcelain) ]]; then - echo "Error: There are uncommitted changes. Please commit them before building." - exit 1 -fi - rm -rf target/ # Clean and build Angular project diff --git a/nise-replay-viewer/Build.sh b/nise-replay-viewer/Build.sh new file mode 100755 index 0000000..ac1974c --- /dev/null +++ b/nise-replay-viewer/Build.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Set variables +IMAGE_NAME="nise-replay-viewer" +IMAGE_REGISTRY="git.gengo.tech/nuff" +IMAGE_VERSION="latest" + +rm -rf dist/ + +# Clean and build Angular project +source /usr/share/nvm/init-nvm.sh +nvm use 18.19 +npm run build +if [ $? -ne 0 ]; then + echo "ng build failed" + exit 1 +fi + +# Build and push Docker image +docker build . -t $IMAGE_NAME:$IMAGE_VERSION +if [ $? -ne 0 ]; then + echo "Docker build failed" + exit 1 +fi + +docker tag $IMAGE_NAME:$IMAGE_VERSION $IMAGE_REGISTRY/$IMAGE_NAME:$IMAGE_VERSION +docker push $IMAGE_REGISTRY/$IMAGE_NAME:$IMAGE_VERSION +if [ "$?" != "0" ]; then + echo "Error: Failed to push $IMAGE_REGISTRY/$IMAGE_NAME:$IMAGE_VERSION" + exit 1 +fi + +echo "Docker image pushed successfully to $IMAGE_REGISTRY/$IMAGE_NAME:$IMAGE_VERSION" diff --git a/nise-replay-viewer/Dockerfile b/nise-replay-viewer/Dockerfile new file mode 100644 index 0000000..f9f0f98 --- /dev/null +++ b/nise-replay-viewer/Dockerfile @@ -0,0 +1,10 @@ +FROM openresty/openresty:focal + +RUN rm -rf /usr/share/nginx/html/* + +COPY dist/ /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/nise-replay-viewer/README.md b/nise-replay-viewer/README.md new file mode 100644 index 0000000..7b60d67 --- /dev/null +++ b/nise-replay-viewer/README.md @@ -0,0 +1,46 @@ +![](./public/gitlogo.png) + +![](https://img.shields.io/badge/status-in_development-blue) + +Replay Inspector is a beatmap/replay analyzer and editor for [osu!](https://osu.ppy.sh/) and is currently in development phase. + +> Inspector is NOT a fork of abstrakt8's rewind, and it has been developed from ground up using same utilites. This project was developed with simplicity in mind using beginner friendly frameworks and easy structure. + +## Geting started + +To use the public version of Replay Inspector, you can follow [click](https://edit.assist.games). + +If you wanna clone and use it locally, proceed by + +``` +git clone https://github.com/cunev/replay-inspector +``` + +then install packages + +``` +bun install +``` + +and run the editor + + +``` +bun run dev +``` + +## Features +- View replay path and beatmap +- Seek through replay +- View clicks +- Enable/disable hardrock +- Modify map metadata +- Analyze clicks, frametimes and release times + +## In development +- Export replays +- Modify path +- Modify keypresses +- Music playback +- Shortcuts + diff --git a/nise-replay-viewer/components.json b/nise-replay-viewer/components.json new file mode 100644 index 0000000..29ca57c --- /dev/null +++ b/nise-replay-viewer/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/globals.css", + "baseColor": "neutral", + "cssVariables": true + }, + "aliases": { + "components": "@/interface/components", + "utils": "@/lib/utils" + } +} \ No newline at end of file diff --git a/nise-replay-viewer/dp12.png b/nise-replay-viewer/dp12.png new file mode 100644 index 0000000..43617fb Binary files /dev/null and b/nise-replay-viewer/dp12.png differ diff --git a/nise-replay-viewer/index.html b/nise-replay-viewer/index.html new file mode 100644 index 0000000..ef2506e --- /dev/null +++ b/nise-replay-viewer/index.html @@ -0,0 +1,26 @@ + + + + + + + Replay Inspector + + + + + + + + + + + + + +
+
+ + + + \ No newline at end of file diff --git a/nise-replay-viewer/nginx.conf b/nise-replay-viewer/nginx.conf new file mode 100644 index 0000000..0c8f3b4 --- /dev/null +++ b/nise-replay-viewer/nginx.conf @@ -0,0 +1,29 @@ +server { + + gzip on; + gzip_static on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + gzip_proxied no-cache no-store private expired auth; + gzip_min_length 1000; + + listen 80; + + resolver local=on ipv6=off; + resolver_timeout 5s; + + root /usr/share/nginx/html; + + location ~ /index.html { + add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; + } + + location ~ .*\.css$|.*\.js$ { + add_header Cache-Control 'max-age=31449600'; + } + + location / { + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + +} diff --git a/nise-replay-viewer/osu-parsers/.eslintignore b/nise-replay-viewer/osu-parsers/.eslintignore new file mode 100644 index 0000000..d82b4f2 --- /dev/null +++ b/nise-replay-viewer/osu-parsers/.eslintignore @@ -0,0 +1,2 @@ +/** +!/src \ No newline at end of file diff --git a/nise-replay-viewer/osu-parsers/.eslintrc.json b/nise-replay-viewer/osu-parsers/.eslintrc.json new file mode 100644 index 0000000..3e006a5 --- /dev/null +++ b/nise-replay-viewer/osu-parsers/.eslintrc.json @@ -0,0 +1,180 @@ +{ + "env": { + "node": true + }, + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 11 + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "plugins": [ + "@typescript-eslint" + ], + "rules": { + /* Best Practices */ + "accessor-pairs": ["error", { + "setWithoutGet": true + }], + "curly": ["error", "multi-line"], + "dot-location": ["error", "property"], + "grouped-accessor-pairs": ["error", "getBeforeSet"], + "eqeqeq": ["error", "always"], + "no-case-declarations": "error", + "no-else-return": "error", + "no-fallthrough": "off", + "no-floating-decimal": "error", + "no-multi-spaces": "error", + "no-useless-escape": "error", + + /* Variables */ + "no-shadow": "off", + "no-unused-vars": "off", + "no-use-before-define": "off", + + /* Stylistic Issues */ + "block-spacing": "error", + "brace-style": ["error", "stroustrup"], + "comma-dangle": ["error", "always-multiline"], + "comma-spacing": ["error", { + "before": false, + "after": true + }], + "comma-style": ["error", "last"], + "eol-last": ["error", "always"], + "indent": ["error", 2, { + "SwitchCase": 1 + }], + "key-spacing": ["error", { + "beforeColon": false + }], + "keyword-spacing": ["error", { + "overrides": { + "else": { "before": false, "after": true } + } + }], + "linebreak-style": "off", + "multiline-comment-style": ["error", "starred-block"], + "newline-per-chained-call": ["error", { + "ignoreChainWithDepth": 2 + }], + "no-multiple-empty-lines": ["error", { + "max": 1, + "maxEOF": 0 + }], + "no-trailing-spaces": ["error", { + "ignoreComments": true + }], + "no-whitespace-before-property": "error", + "object-curly-spacing": ["error", "always"], + "object-property-newline": ["error", { + "allowMultiplePropertiesPerLine": false + }], + "padding-line-between-statements": ["error", + { + "blankLine": "always", + "prev": [ + "block-like", + "multiline-block-like", + "multiline-expression" + ], + "next": "*" + }, + { + "blankLine": "always", + "prev": "*", + "next": [ + "block-like", + "multiline-block-like", + "return" + ] + }, + { + "blankLine": "any", + "prev": "case", + "next": "case" + }, + { + "blankLine": "always", + "prev": ["let", "var", "const"], + "next": ["expression", "multiline-expression"] + }, + { + "blankLine": "always", + "prev": ["expression", "multiline-expression"], + "next": ["let", "var", "const"] + }, + { + "blankLine": "always", + "prev": "*", + "next": ["function", "class"] + } + ], + "quotes": ["error", "single"], + "semi": "off", + "semi-spacing": ["error", { + "before": false, + "after": true + }], + "space-before-blocks": "error", + "space-before-function-paren": ["error", "never"], + "space-infix-ops": "error", + "spaced-comment": "error", + "switch-colon-spacing": "error", + + /* ECMAScript 6 */ + "arrow-parens": "error", + "arrow-spacing": "error", + "no-duplicate-imports": "error", + "no-useless-constructor": "off", + "no-var": "error", + "object-shorthand": "error", + "prefer-arrow-callback": "error" + }, + "overrides": [ + { + "files": [ + "./**/*.ts", + "./**/*.d.ts" + ], + "rules": { + // This rule is disabled for reverse indexing in enums + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-var-requires": "error", + + "@typescript-eslint/semi": ["error", "always"], + "@typescript-eslint/no-shadow": "off", + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/no-use-before-define": ["error", { + "functions": false, + "classes": false, + "variables": true + }], + "@typescript-eslint/no-useless-constructor": "error", + "@typescript-eslint/explicit-module-boundary-types": "error", + + "indent": "off", + "@typescript-eslint/indent": ["error", 2] + } + }, + { + "files": [ + "./**/*.js", + "./**/*.cjs", + "./**/*.mjs" + ], + "rules": { + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/semi": "off", + "@typescript-eslint/no-shadow": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "no-undef": "off" + } + } + ] +} diff --git a/nise-replay-viewer/osu-parsers/.npmignore b/nise-replay-viewer/osu-parsers/.npmignore new file mode 100644 index 0000000..dacca7a --- /dev/null +++ b/nise-replay-viewer/osu-parsers/.npmignore @@ -0,0 +1,9 @@ +/** +!/lib +!/lib/** +!.eslintignore +!.eslintrc.json +!.npmignore +!LICENSE +!package.json +!README.md diff --git a/nise-replay-viewer/osu-parsers/LICENSE b/nise-replay-viewer/osu-parsers/LICENSE new file mode 100644 index 0000000..07b9795 --- /dev/null +++ b/nise-replay-viewer/osu-parsers/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2023 Kionell + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/nise-replay-viewer/osu-parsers/README.md b/nise-replay-viewer/osu-parsers/README.md new file mode 100644 index 0000000..f05d2cb --- /dev/null +++ b/nise-replay-viewer/osu-parsers/README.md @@ -0,0 +1,243 @@ +# osu-parsers +[![CodeFactor](https://img.shields.io/codefactor/grade/github/kionell/osu-parsers)](https://www.codefactor.io/repository/github/kionell/osu-parsers) +[![License](https://img.shields.io/github/license/kionell/osu-parsers)](https://github.com/kionell/osu-parsers/blob/master/LICENSE) +[![Package](https://img.shields.io/npm/v/osu-parsers)](https://www.npmjs.com/package/osu-parsers) + + +A bundle of decoders/encoders for osu! file formats based on the osu!lazer source code. + +- Written in TypeScript. +- Based on the osu!lazer source code. +- Allows you to parse beatmaps of any osu! game mode. +- Supports beatmap conversion between different game modes. +- Works in browsers. + +## Installation + +Add a new dependency to your project via npm: + +```bash +npm install osu-parsers +``` + +## Dependencies + +This package comes with built-in LZMA codec as it is required for replay processing. +All classes and their typings can be found in [osu-classes](https://github.com/kionell/osu-classes) package which is a peer dependency and must be installed separately. + +## Supported file formats + +- [.osu](https://osu.ppy.sh/wiki/en/Client/File_formats/osu_%28file_format%29) - fully supported (decoding/encoding) +- [.osb](https://osu.ppy.sh/wiki/en/Client/File_formats/osb_%28file_format%29) - fully supported (decoding/encoding) +- [.osr](https://osu.ppy.sh/wiki/en/Client/File_formats/osr_%28file_format%29) - fully supported (decoding/encoding) + +## Beatmap decoding + +Beatmap decoder is used to read `.osu` files and convert them to the objects of plain [Beatmap](https://kionell.github.io/osu-classes/classes/Beatmap.html) type. +Note that plain beatmap objects can't be used to get max combo, star rating and performance as they don't have ruleset specific data. To get correct beatmap data, beatmap objects should be converted using one of the supported [rulesets](https://github.com/kionell/osu-parsers#rulesets). + +There are 4 ways to read data using this decoders: +- via file path - async +- via data buffer - sync +- via string - sync +- via array of split lines - sync + +By default, beatmap decoder will decode both beatmap and storyboard. If you want to decode beatmap without storyboard, you can pass `false` as the second parameter to any of the methods. +There is also a support for partial beatmap decoding which allows you to skip unnecessary sections. + +### Example of beatmap decoding + +```js +import { BeatmapDecoder } from 'osu-parsers' + +const path = 'path/to/your/file.osu'; +const data = 'osu file format v14...'; + +// This is optional and true by default. +const shouldParseSb = true; + +const decoder = new BeatmapDecoder(); +const beatmap1 = await decoder.decodeFromPath(path, shouldParseSb); + +// Partial beatmap decoding without unnecessary sections. +const beatmap2 = decoder.decodeFromString(data, { + parseGeneral: false, + parseEditor: false, + parseMetadata: false, + parseDifficulty: false, + parseEvents: false, + parseTimingPoints: false, + parseHitObjects: false, + parseStoryboard: false, + parseColours: false, +}); + +console.log(beatmap1) // Beatmap object. +console.log(beatmap2) // Another Beatmap object. +``` + +## Storyboard decoding + +Storyboard decoder is used to read both `.osu` and `.osb` files and convert them to the [Storyboard](https://kionell.github.io/osu-classes/classes/Storyboard.html) objects. + +As in beatmap decoder, there are 4 ways to decode your `.osu` and `.osb` files: +- via file path - async +- via data buffer - sync +- via string - sync +- via array of split lines - sync + +### Example of storyboard decoding + +```js +import { StoryboardDecoder } from 'osu-parsers' + +const pathToOsb = 'path/to/your/file.osb'; +const pathToOsu = 'path/to/your/file.osu'; + +const decoder = new StoryboardDecoder(); + +// Parse a single storyboard file (from .osb) for beatmaps that doesn't have internal storyboard (from .osu) +const storyboard1 = await decoder.decodeFromPath(pathToOsb); + +// Combines main storyboard (from .osu) with secondary storyboard (from .osb) +const storyboard2 = await decoder.decodeFromPath(pathToOsu, pathToOsb); + +console.log(storyboard1); // Storyboard object. +console.log(storyboard2); // Another Storyboard object. +``` + +## Score & replay decoding + +Score decoder is used to decode `.osr` files and convert them to the [Score](https://kionell.github.io/osu-classes/classes/Score.html) objects. +Score object contains score information and replay data of plain [Replay](https://kionell.github.io/osu-classes/classes/Replay.html) type. +Note that all `.osr` files contain raw legacy frame data that was initially intended for osu!standard only. To get correct data, replay objects should be converted using one of the supported [rulesets](https://github.com/kionell/osu-parsers#rulesets). +This decoder is based on external LZMA library and works asynchronously. + +There are 2 ways to read data through this decoder: +- via file path - async +- via buffer - async + +By default, score decoder will decode both score information and replay. If you want to decode score information without replay, you can pass `false` as the second parameter to any of the methods. + +### Example of score & replay decoding + +```js +import { ScoreDecoder } from 'osu-parsers' + +const path = 'path/to/your/file.osr'; + +// This is optional and true by default. +const parseReplay = true; + +const decoder = new ScoreDecoder(); + +const score = await decoder.decodeFromPath(path, parseReplay) + +console.log(score.info); // ScoreInfo object. +console.log(score.replay); // Replay object or null. +``` + +## Encoding + +All objects parsed by these decoders can easily be stringified and written to the files. +Note that encoders will write object data without any changes. For example, if you try to encode beatmap with applied mods, it will write modded values! + +When encoding is complete you can import resulting files to the game. + +### Example of beatmap encoding + +```js +import { BeatmapDecoder, BeatmapEncoder } from 'osu-parsers' + +const decodePath = 'path/to/your/file.osu'; +const shouldParseSb = true; + +const decoder = new BeatmapDecoder(); +const encoder = new BeatmapEncoder(); + +const beatmap = await decoder.decodeFromPath(decodePath, shouldParseSb); + +// Do your stuff with beatmap... + +const encodePath = 'path/to/your/file.osu'; + +// Write IBeatmap object to an .osu file. +await encoder.encodeToPath(encodePath, beatmap); + +// You can also encode IBeatmap object to a string. +const stringified = encoder.encodeToString(beatmap); +``` + +### Example of storyboard encoding + +```js +import { StoryboardDecoder, StoryboardEncoder } from 'osu-parsers' + +const decodePath = 'path/to/your/file.osb'; + +const decoder = new StoryboardDecoder(); +const encoder = new StoryboardEncoder(); + +const storyboard = await decoder.decodeFromPath(decodePath); + +// Do your stuff with storyboard... + +const encodePath = 'path/to/your/file.osb'; + +// Write Storyboard object to an .osb file. +await encoder.encodeToPath(encodePath, storyboard); + +// You can also encode Storyboard object to a string. +const stringified = encoder.encodeToString(storyboard); +``` + +### Example of score & replay encoding + +```js +import { ScoreDecoder, ScoreEncoder } from 'osu-parsers' + +const decodePath = 'path/to/your/file.osr'; + +const decoder = new ScoreDecoder(); +const encoder = new ScoreEncoder(); + +const score = await decoder.decodeFromPath(decodePath); + +// Do your stuff with score info and replay... + +const encodePath = 'path/to/your/file.osr'; + +// Write IScore object to an .osr file. +await encoder.encodeToPath(encodePath, score); + +// You can also encode IScore object to a buffer. +const buffer = await encoder.encodeToBuffer(score); +``` + +## Rulesets + +This library by itself doesn't provide any tools for difficulty and performance calculation!!!! +If you are looking for something related to this, then rulesets may come in handy for you. +Rulesets are separate libraries based on the classes from the [osu-classes](https://github.com/kionell/osu-classes.git) project. They allow you to work with gamemode specific stuff as difficulty, performance, mods and max combo calculation. Because of the shared logic between all of the rulesets they are compatible between each other. If you want, you can even write your own custom ruleset! +The great thing about all this stuff is a beatmap and replay conversion. Any beatmap or replay can be used with any ruleset library as long as they implement the same interfaces. + +There are 4 basic rulesets that support parsed beatmaps from this decoder: + +- [osu-standard-stable](https://github.com/kionell/osu-standard-stable.git) - The osu!std ruleset based on the osu!lazer source code. +- [osu-taiko-stable](https://github.com/kionell/osu-taiko-stable.git) - The osu!taiko ruleset based on the osu!lazer source code. +- [osu-catch-stable](https://github.com/kionell/osu-catch-stable.git) - The osu!catch ruleset based on the osu!lazer source code. +- [osu-mania-stable](https://github.com/kionell/osu-mania-stable.git) - The osu!mania ruleset based on the osu!lazer source code. + +You can also try existing [osu-pp-calculator](https://github.com/kionell/osu-pp-calculator) package. It's a wrapper for all 4 rulesets above with a lot of extra useful stuff like score simulation and beatmap downloading. + +## Documentation + +Auto-generated documentation is available [here](https://kionell.github.io/osu-parsers/). + +## Contributing + +This project is being developed personally by me on pure enthusiasm. If you want to help with development or fix a problem, then feel free to create a new pull request. For major changes, please open an issue first to discuss what you would like to change. + +## License + +This project is licensed under the MIT License - see the [LICENSE](https://choosealicense.com/licenses/mit/) for details. diff --git a/nise-replay-viewer/osu-parsers/lib/browser.mjs b/nise-replay-viewer/osu-parsers/lib/browser.mjs new file mode 100644 index 0000000..644c54b --- /dev/null +++ b/nise-replay-viewer/osu-parsers/lib/browser.mjs @@ -0,0 +1,3282 @@ +import { + Color4, + EventType, + StoryboardSample, + StoryboardAnimation, + Vector2, + StoryboardSprite, + LayerType, + StoryboardVideo, + CompoundType, + CommandType, + ParameterType, + BlendingParameters, + Origins, + Anchor, + LoopType, + BeatmapBreakEvent, + SampleSet, + HitObject, + SliderPath, + CommandLoop, + CommandTrigger, + HitType, + HitSound, + PathType, + EffectType, + TimeSignature, + ControlPointType, + ReplayButtonState, + LegacyReplayFrame, + Storyboard, + SampleBank, + PathPoint, + HitSample, + TimingPoint, + DifficultyPoint, + EffectPoint, + SamplePoint, + LifeBarFrame, + Beatmap, + ScoreInfo, + Replay, + Score, +} from "osu-classes"; +import { decompress, compress } from "lzma-js-simple-v2"; + +class Parsing { + static parseInt(input, parseLimit = this.MAX_PARSE_VALUE, allowNaN = false) { + return this._getValue(parseInt(input), parseLimit, allowNaN); + } + static parseFloat( + input, + parseLimit = this.MAX_PARSE_VALUE, + allowNaN = false + ) { + return this._getValue(parseFloat(input), parseLimit, allowNaN); + } + static parseEnum(enumObj, input) { + const value = input.trim(); + const rawValue = parseInt(value); + + if (rawValue in enumObj) { + return rawValue; + } + + if (value in enumObj) { + return enumObj[value]; + } + + throw new Error("Unknown enum value!"); + } + static parseByte(input) { + const value = parseInt(input); + + if (value < 0) { + throw new Error("Value must be greater than 0!"); + } + + if (value > 255) { + throw new Error("Value must be less than 255!"); + } + + return this._getValue(value); + } + static _getValue(value, parseLimit = this.MAX_PARSE_VALUE, allowNaN = false) { + if (value < -parseLimit) { + throw new Error("Value is too low!"); + } + + if (value > parseLimit) { + throw new Error("Value is too high!"); + } + + if (!allowNaN && Number.isNaN(value)) { + throw new Error("Not a number"); + } + + return value; + } +} +Parsing.MAX_COORDINATE_VALUE = 131072; +Parsing.MAX_PARSE_VALUE = 2147483647; + +class BeatmapColorDecoder { + static handleLine(line, output) { + const [key, ...values] = line.split(":"); + const rgba = values + .join(":") + .trim() + .split(",") + .map((c) => Parsing.parseByte(c)); + + if (rgba.length !== 3 && rgba.length !== 4) { + throw new Error( + `Color specified in incorrect format (should be R,G,B or R,G,B,A): ${rgba.join( + "," + )}` + ); + } + + const color = new Color4(rgba[0], rgba[1], rgba[2], rgba[3]); + + this.addColor(color, output, key.trim()); + } + static addColor(color, output, key) { + if (key === "SliderTrackOverride") { + output.colors.sliderTrackColor = color; + + return; + } + + if (key === "SliderBorder") { + output.colors.sliderBorderColor = color; + + return; + } + + if (key.startsWith("Combo")) { + output.colors.comboColors.push(color); + } + } +} + +class BeatmapDifficultyDecoder { + static handleLine(line, beatmap) { + const [key, ...values] = line.split(":"); + const value = values.join(":").trim(); + + switch (key.trim()) { + case "CircleSize": + beatmap.difficulty.circleSize = Parsing.parseFloat(value); + break; + case "HPDrainRate": + beatmap.difficulty.drainRate = Parsing.parseFloat(value); + break; + case "OverallDifficulty": + beatmap.difficulty.overallDifficulty = Parsing.parseFloat(value); + break; + case "ApproachRate": + beatmap.difficulty.approachRate = Parsing.parseFloat(value); + break; + case "SliderMultiplier": + beatmap.difficulty.sliderMultiplier = Parsing.parseFloat(value); + break; + case "SliderTickRate": + beatmap.difficulty.sliderTickRate = Parsing.parseFloat(value); + } + } +} + +class BeatmapEditorDecoder { + static handleLine(line, beatmap) { + const [key, ...values] = line.split(":"); + const value = values.join(":").trim(); + + switch (key.trim()) { + case "Bookmarks": + beatmap.editor.bookmarks = value.split(",").map((v) => +v); + break; + case "DistanceSpacing": + beatmap.editor.distanceSpacing = Math.max(0, Parsing.parseFloat(value)); + break; + case "BeatDivisor": + beatmap.editor.beatDivisor = Parsing.parseInt(value); + break; + case "GridSize": + beatmap.editor.gridSize = Parsing.parseInt(value); + break; + case "TimelineZoom": + beatmap.editor.timelineZoom = Math.max(0, Parsing.parseFloat(value)); + } + } +} + +class StoryboardEventDecoder { + static handleLine(line, storyboard) { + const depth = this._getDepth(line); + + if (depth > 0) { + line = line.substring(depth); + } + + if (depth < 2 && this._storyboardSprite) { + this._timelineGroup = this._storyboardSprite.timelineGroup; + } + + switch (depth) { + case 0: + return this._handleElement(line, storyboard); + case 1: + return this._handleCompoundOrCommand(line); + case 2: + return this._handleCommand(line); + } + } + static _handleElement(line, storyboard) { + let _a; + const data = line.split(","); + const eventType = this.parseEventType(data[0]); + + if ( + (_a = this._storyboardSprite) === null || _a === void 0 + ? void 0 + : _a.hasCommands + ) { + this._storyboardSprite.updateCommands(); + this._storyboardSprite.adjustTimesToCommands(); + this._storyboardSprite.resetValuesToCommands(); + } + + switch (eventType) { + case EventType.Video: { + const layer = storyboard.getLayerByType(LayerType.Video); + const offset = Parsing.parseInt(data[1]); + const path = data[2].replace(/"/g, ""); + + layer.elements.push(new StoryboardVideo(path, offset)); + + return; + } + case EventType.Sprite: { + const layer = storyboard.getLayerByType(this.parseLayerType(data[1])); + const origin = this.parseOrigin(data[2]); + const anchor = this.convertOrigin(origin); + const path = data[3].replace(/"/g, ""); + const x = Parsing.parseFloat(data[4], Parsing.MAX_COORDINATE_VALUE); + const y = Parsing.parseFloat(data[5], Parsing.MAX_COORDINATE_VALUE); + + this._storyboardSprite = new StoryboardSprite( + path, + origin, + anchor, + new Vector2(x, y) + ); + layer.elements.push(this._storyboardSprite); + + return; + } + case EventType.Animation: { + const layer = storyboard.getLayerByType(this.parseLayerType(data[1])); + const origin = this.parseOrigin(data[2]); + const anchor = this.convertOrigin(origin); + const path = data[3].replace(/"/g, ""); + const x = Parsing.parseFloat(data[4], Parsing.MAX_COORDINATE_VALUE); + const y = Parsing.parseFloat(data[5], Parsing.MAX_COORDINATE_VALUE); + const frameCount = Parsing.parseInt(data[6]); + let frameDelay = Parsing.parseFloat(data[7]); + + if (storyboard.fileFormat < 6) { + frameDelay = Math.round(0.015 * frameDelay) * 1.186 * (1000 / 60); + } + + const loopType = this.parseLoopType(data[8]); + + this._storyboardSprite = new StoryboardAnimation( + path, + origin, + anchor, + new Vector2(x, y), + frameCount, + frameDelay, + loopType + ); + layer.elements.push(this._storyboardSprite); + + return; + } + case EventType.Sample: { + const time = Parsing.parseFloat(data[1]); + const layer = storyboard.getLayerByType(this.parseLayerType(data[2])); + const path = data[3].replace(/"/g, ""); + const volume = data.length > 4 ? Parsing.parseInt(data[4]) : 100; + const sample = new StoryboardSample(path, time, volume); + + layer.elements.push(sample); + } + } + } + static _handleCompoundOrCommand(line) { + let _a, _b; + const data = line.split(","); + const compoundType = data[0]; + + switch (compoundType) { + case CompoundType.Trigger: { + this._timelineGroup = + (_a = this._storyboardSprite) === null || _a === void 0 + ? void 0 + : _a.addTrigger( + data[1], + data.length > 2 ? Parsing.parseFloat(data[2]) : -Infinity, + data.length > 3 ? Parsing.parseFloat(data[3]) : Infinity, + data.length > 4 ? Parsing.parseInt(data[4]) : 0 + ); + + return; + } + case CompoundType.Loop: { + this._timelineGroup = + (_b = this._storyboardSprite) === null || _b === void 0 + ? void 0 + : _b.addLoop( + Parsing.parseFloat(data[1]), + Math.max(0, Parsing.parseInt(data[2]) - 1) + ); + + return; + } + + default: + this._handleCommand(line); + } + } + static _handleCommand(line) { + let _a, _b, _c, _d, _e, _f, _g, _h, _j; + const data = line.split(","); + const type = data[0]; + const easing = Parsing.parseInt(data[1]); + const startTime = Parsing.parseInt(data[2]); + const endTime = Parsing.parseInt(data[3] || data[2]); + + switch (type) { + case CommandType.Fade: { + const startValue = Parsing.parseFloat(data[4]); + const endValue = + data.length > 5 ? Parsing.parseFloat(data[5]) : startValue; + + (_a = this._timelineGroup) === null || _a === void 0 + ? void 0 + : _a.alpha.add( + type, + easing, + startTime, + endTime, + startValue, + endValue + ); + + return; + } + case CommandType.Scale: { + const startValue = Parsing.parseFloat(data[4]); + const endValue = + data.length > 5 ? Parsing.parseFloat(data[5]) : startValue; + + (_b = this._timelineGroup) === null || _b === void 0 + ? void 0 + : _b.scale.add( + type, + easing, + startTime, + endTime, + startValue, + endValue + ); + + return; + } + case CommandType.VectorScale: { + const startX = Parsing.parseFloat(data[4]); + const startY = Parsing.parseFloat(data[5]); + const endX = data.length > 6 ? Parsing.parseFloat(data[6]) : startX; + const endY = data.length > 7 ? Parsing.parseFloat(data[7]) : startY; + + (_c = this._timelineGroup) === null || _c === void 0 + ? void 0 + : _c.vectorScale.add( + type, + easing, + startTime, + endTime, + new Vector2(startX, startY), + new Vector2(endX, endY) + ); + + return; + } + case CommandType.Rotation: { + const startValue = Parsing.parseFloat(data[4]); + const endValue = + data.length > 5 ? Parsing.parseFloat(data[5]) : startValue; + + (_d = this._timelineGroup) === null || _d === void 0 + ? void 0 + : _d.rotation.add( + type, + easing, + startTime, + endTime, + startValue, + endValue + ); + + return; + } + case CommandType.Movement: { + const startX = Parsing.parseFloat(data[4]); + const startY = Parsing.parseFloat(data[5]); + const endX = data.length > 6 ? Parsing.parseFloat(data[6]) : startX; + const endY = data.length > 7 ? Parsing.parseFloat(data[7]) : startY; + + (_e = this._timelineGroup) === null || _e === void 0 + ? void 0 + : _e.x.add( + CommandType.MovementX, + easing, + startTime, + endTime, + startX, + endX + ); + (_f = this._timelineGroup) === null || _f === void 0 + ? void 0 + : _f.y.add( + CommandType.MovementY, + easing, + startTime, + endTime, + startY, + endY + ); + + return; + } + case CommandType.MovementX: { + const startValue = Parsing.parseFloat(data[4]); + const endValue = + data.length > 5 ? Parsing.parseFloat(data[5]) : startValue; + + (_g = this._timelineGroup) === null || _g === void 0 + ? void 0 + : _g.x.add(type, easing, startTime, endTime, startValue, endValue); + + return; + } + case CommandType.MovementY: { + const startValue = Parsing.parseFloat(data[4]); + const endValue = + data.length > 5 ? Parsing.parseFloat(data[5]) : startValue; + + (_h = this._timelineGroup) === null || _h === void 0 + ? void 0 + : _h.y.add(type, easing, startTime, endTime, startValue, endValue); + + return; + } + case CommandType.Color: { + const startRed = Parsing.parseFloat(data[4]); + const startGreen = Parsing.parseFloat(data[5]); + const startBlue = Parsing.parseFloat(data[6]); + const endRed = data.length > 7 ? Parsing.parseFloat(data[7]) : startRed; + const endGreen = + data.length > 8 ? Parsing.parseFloat(data[8]) : startGreen; + const endBlue = + data.length > 9 ? Parsing.parseFloat(data[9]) : startBlue; + + (_j = this._timelineGroup) === null || _j === void 0 + ? void 0 + : _j.color.add( + type, + easing, + startTime, + endTime, + new Color4(startRed, startGreen, startBlue, 1), + new Color4(endRed, endGreen, endBlue, 1) + ); + + return; + } + case CommandType.Parameter: { + return this._handleParameterCommand(data); + } + } + + throw new Error(`Unknown command type: ${type}`); + } + static _handleParameterCommand(data) { + let _a, _b, _c; + const type = CommandType.Parameter; + const easing = Parsing.parseInt(data[1]); + const startTime = Parsing.parseInt(data[2]); + const endTime = Parsing.parseInt(data[3] || data[2]); + const parameter = data[4]; + + switch (parameter) { + case ParameterType.BlendingMode: { + const startValue = BlendingParameters.Additive; + const endValue = + startTime === endTime + ? BlendingParameters.Additive + : BlendingParameters.Inherit; + + (_a = this._timelineGroup) === null || _a === void 0 + ? void 0 + : _a.blendingParameters.add( + type, + easing, + startTime, + endTime, + startValue, + endValue, + parameter + ); + + return; + } + case ParameterType.HorizontalFlip: + (_b = this._timelineGroup) === null || _b === void 0 + ? void 0 + : _b.flipH.add( + type, + easing, + startTime, + endTime, + true, + startTime === endTime, + parameter + ); + + return; + case ParameterType.VerticalFlip: { + (_c = this._timelineGroup) === null || _c === void 0 + ? void 0 + : _c.flipV.add( + type, + easing, + startTime, + endTime, + true, + startTime === endTime, + parameter + ); + + return; + } + } + + throw new Error(`Unknown parameter type: ${parameter}`); + } + static parseEventType(input) { + if (input.startsWith(" ") || input.startsWith("_")) { + return EventType.StoryboardCommand; + } + + try { + return Parsing.parseEnum(EventType, input); + } catch { + throw new Error(`Unknown event type: ${input}`); + } + } + static parseLayerType(input) { + try { + return Parsing.parseEnum(LayerType, input); + } catch { + throw new Error(`Unknown layer type: ${input}`); + } + } + static parseOrigin(input) { + try { + return Parsing.parseEnum(Origins, input); + } catch { + return Origins.TopLeft; + } + } + static convertOrigin(origin) { + switch (origin) { + case Origins.TopLeft: + return Anchor.TopLeft; + case Origins.TopCentre: + return Anchor.TopCentre; + case Origins.TopRight: + return Anchor.TopRight; + case Origins.CentreLeft: + return Anchor.CentreLeft; + case Origins.Centre: + return Anchor.Centre; + case Origins.CentreRight: + return Anchor.CentreRight; + case Origins.BottomLeft: + return Anchor.BottomLeft; + case Origins.BottomCentre: + return Anchor.BottomCentre; + case Origins.BottomRight: + return Anchor.BottomRight; + } + + return Anchor.TopLeft; + } + static parseLoopType(input) { + try { + return Parsing.parseEnum(LoopType, input); + } catch { + return LoopType.LoopForever; + } + } + static _getDepth(line) { + let depth = 0; + + for (const char of line) { + if (char !== " " && char !== "_") { + break; + } + + ++depth; + } + + return depth; + } +} + +class BeatmapEventDecoder { + static handleLine(line, beatmap, sbLines, offset) { + const data = line.split(",").map((v, i) => (i ? v.trim() : v)); + const eventType = StoryboardEventDecoder.parseEventType(data[0]); + + switch (eventType) { + case EventType.Background: + beatmap.events.backgroundPath = data[2].replace(/"/g, ""); + break; + case EventType.Break: { + const start = Parsing.parseFloat(data[1]) + offset; + const end = Math.max(start, Parsing.parseFloat(data[2]) + offset); + const breakEvent = new BeatmapBreakEvent(start, end); + + if (!beatmap.events.breaks) { + beatmap.events.breaks = []; + } + + beatmap.events.breaks.push(breakEvent); + break; + } + case EventType.Video: + case EventType.Sample: + case EventType.Sprite: + case EventType.Animation: + case EventType.StoryboardCommand: + if (sbLines) { + sbLines.push(line); + } + } + } +} + +class BeatmapGeneralDecoder { + static handleLine(line, beatmap, offset) { + const [key, ...values] = line.split(":"); + const value = values.join(":").trim(); + + switch (key.trim()) { + case "AudioFilename": + beatmap.general.audioFilename = value; + break; + case "AudioHash": + beatmap.general.audioHash = value; + break; + case "OverlayPosition": + beatmap.general.overlayPosition = value; + break; + case "SkinPreference": + beatmap.general.skinPreference = value; + break; + case "AudioLeadIn": + beatmap.general.audioLeadIn = Parsing.parseInt(value); + break; + case "PreviewTime": + beatmap.general.previewTime = Parsing.parseInt(value) + offset; + break; + case "Countdown": + beatmap.general.countdown = Parsing.parseInt(value); + break; + case "StackLeniency": + beatmap.general.stackLeniency = Parsing.parseFloat(value); + break; + case "Mode": + beatmap.originalMode = Parsing.parseInt(value); + break; + case "CountdownOffset": + beatmap.general.countdownOffset = Parsing.parseInt(value); + break; + case "SampleSet": + beatmap.general.sampleSet = SampleSet[value]; + break; + case "LetterboxInBreaks": + beatmap.general.letterboxInBreaks = value === "1"; + break; + case "StoryFireInFront": + beatmap.general.storyFireInFront = value === "1"; + break; + case "UseSkinSprites": + beatmap.general.useSkinSprites = value === "1"; + break; + case "AlwaysShowPlayfield": + beatmap.general.alwaysShowPlayfield = value === "1"; + break; + case "EpilepsyWarning": + beatmap.general.epilepsyWarning = value === "1"; + break; + case "SpecialStyle": + beatmap.general.specialStyle = value === "1"; + break; + case "WidescreenStoryboard": + beatmap.general.widescreenStoryboard = value === "1"; + break; + case "SamplesMatchPlaybackRate": + beatmap.general.samplesMatchPlaybackRate = value === "1"; + } + } +} + +class HittableObject extends HitObject { + constructor() { + super(...arguments); + this.isNewCombo = false; + this.comboOffset = 0; + } + clone() { + const cloned = super.clone(); + + cloned.isNewCombo = this.isNewCombo; + cloned.comboOffset = this.comboOffset; + + return cloned; + } +} + +class HoldableObject extends HitObject { + constructor() { + super(...arguments); + this.endTime = 0; + this.nodeSamples = []; + } + get duration() { + return this.endTime - this.startTime; + } + clone() { + const cloned = super.clone(); + + cloned.endTime = this.endTime; + cloned.nestedHitObjects = this.nestedHitObjects.map((h) => h.clone()); + cloned.nodeSamples = this.nodeSamples.map((n) => n.map((s) => s.clone())); + + return cloned; + } +} + +class SlidableObject extends HitObject { + constructor() { + super(...arguments); + this.repeats = 0; + this.velocity = 1; + this.path = new SliderPath(); + this.legacyLastTickOffset = 36; + this.nodeSamples = []; + this.isNewCombo = false; + this.comboOffset = 0; + } + get duration() { + return this.spans * this.spanDuration; + } + get endTime() { + return this.startTime + this.duration; + } + get spans() { + return this.repeats + 1; + } + set spans(value) { + this.repeats = value - 1; + } + get spanDuration() { + return this.distance / this.velocity; + } + get distance() { + return this.path.distance; + } + set distance(value) { + this.path.distance = value; + } + applyDefaultsToSelf(controlPoints, difficulty) { + super.applyDefaultsToSelf(controlPoints, difficulty); + + const timingPoint = controlPoints.timingPointAt(this.startTime); + const difficultyPoint = controlPoints.difficultyPointAt(this.startTime); + const scoringDistance = + SlidableObject.BASE_SCORING_DISTANCE * + difficulty.sliderMultiplier * + difficultyPoint.sliderVelocity; + + this.velocity = scoringDistance / timingPoint.beatLength; + } + clone() { + const cloned = super.clone(); + + cloned.legacyLastTickOffset = this.legacyLastTickOffset; + cloned.nodeSamples = this.nodeSamples.map((n) => n.map((s) => s.clone())); + cloned.velocity = this.velocity; + cloned.repeats = this.repeats; + cloned.path = this.path.clone(); + cloned.isNewCombo = this.isNewCombo; + cloned.comboOffset = this.comboOffset; + + return cloned; + } +} +SlidableObject.BASE_SCORING_DISTANCE = 100; + +class SpinnableObject extends HitObject { + constructor() { + super(...arguments); + this.endTime = 0; + this.isNewCombo = false; + this.comboOffset = 0; + } + get duration() { + return this.endTime - this.startTime; + } + clone() { + const cloned = super.clone(); + + cloned.endTime = this.endTime; + cloned.isNewCombo = this.isNewCombo; + cloned.comboOffset = this.comboOffset; + + return cloned; + } +} + +let FileFormat; + +(function (FileFormat) { + FileFormat["Beatmap"] = ".osu"; + FileFormat["Storyboard"] = ".osb"; + FileFormat["Replay"] = ".osr"; +})(FileFormat || (FileFormat = {})); + +let LineType; + +(function (LineType) { + LineType[(LineType["FileFormat"] = 0)] = "FileFormat"; + LineType[(LineType["Section"] = 1)] = "Section"; + LineType[(LineType["Empty"] = 2)] = "Empty"; + LineType[(LineType["Data"] = 3)] = "Data"; + LineType[(LineType["Break"] = 4)] = "Break"; +})(LineType || (LineType = {})); + +let Section; + +(function (Section) { + Section["General"] = "General"; + Section["Editor"] = "Editor"; + Section["Metadata"] = "Metadata"; + Section["Difficulty"] = "Difficulty"; + Section["Events"] = "Events"; + Section["TimingPoints"] = "TimingPoints"; + Section["Colours"] = "Colours"; + Section["HitObjects"] = "HitObjects"; + Section["Variables"] = "Variables"; + Section["Fonts"] = "Fonts"; + Section["CatchTheBeat"] = "CatchTheBeat"; + Section["Mania"] = "Mania"; +})(Section || (Section = {})); + +const browserFSOperation = function () { + throw new Error( + "Filesystem operations are not available in a browser environment" + ); +}; + +class BeatmapColorEncoder { + static encodeColors(beatmap) { + const colors = beatmap.colors; + + if (Object.keys(colors).length === 1 && !colors.comboColors.length) { + return ""; + } + + const encoded = ["[Colours]"]; + + colors.comboColors.forEach((color, i) => { + encoded.push(`Combo${i + 1}:${color}`); + }); + + if (colors.sliderTrackColor) { + encoded.push(`SliderTrackOverride:${colors.sliderTrackColor}`); + } + + if (colors.sliderBorderColor) { + encoded.push(`SliderBorder:${colors.sliderBorderColor}`); + } + + return encoded.join("\n"); + } +} + +class BeatmapDifficultyEncoder { + static encodeDifficultySection(beatmap) { + const encoded = ["[Difficulty]"]; + const difficulty = beatmap.difficulty; + + encoded.push(`HPDrainRate:${difficulty.drainRate}`); + encoded.push(`CircleSize:${difficulty.circleSize}`); + encoded.push(`OverallDifficulty:${difficulty.overallDifficulty}`); + encoded.push(`ApproachRate:${difficulty.approachRate}`); + encoded.push(`SliderMultiplier:${difficulty.sliderMultiplier}`); + encoded.push(`SliderTickRate:${difficulty.sliderTickRate}`); + + return encoded.join("\n"); + } +} + +class BeatmapEditorEncoder { + static encodeEditorSection(beatmap) { + const encoded = ["[Editor]"]; + const editor = beatmap.editor; + + encoded.push(`Bookmarks:${editor.bookmarks.join(",")}`); + encoded.push(`DistanceSpacing:${editor.distanceSpacing}`); + encoded.push(`BeatDivisor:${editor.beatDivisor}`); + encoded.push(`GridSize:${editor.gridSize}`); + encoded.push(`TimelineZoom:${editor.timelineZoom}`); + + return encoded.join("\n"); + } +} + +class StoryboardEventEncoder { + static encodeEventSection(storyboard) { + const encoded = []; + + encoded.push("[Events]"); + encoded.push("//Background and Video events"); + encoded.push(this.encodeVideos(storyboard)); + encoded.push(this.encodeStoryboard(storyboard)); + + return encoded.join("\n"); + } + static encodeVideos(storyboard) { + const encoded = []; + const video = storyboard.getLayerByType(LayerType.Video); + + if (video.elements.length > 0) { + encoded.push(this.encodeStoryboardLayer(video)); + } + + return encoded.join("\n"); + } + static encodeStoryboard(storyboard) { + const encoded = []; + + encoded.push("//Storyboard Layer 0 (Background)"); + + const background = storyboard.getLayerByType(LayerType.Background); + + if (background.elements.length > 0) { + encoded.push(this.encodeStoryboardLayer(background)); + } + + encoded.push("//Storyboard Layer 1 (Fail)"); + + const fail = storyboard.getLayerByType(LayerType.Fail); + + if (fail.elements.length > 0) { + encoded.push(this.encodeStoryboardLayer(fail)); + } + + encoded.push("//Storyboard Layer 2 (Pass)"); + + const pass = storyboard.getLayerByType(LayerType.Pass); + + if (pass.elements.length > 0) { + encoded.push(this.encodeStoryboardLayer(pass)); + } + + encoded.push("//Storyboard Layer 3 (Foreground)"); + + const foreground = storyboard.getLayerByType(LayerType.Foreground); + + if (foreground.elements.length > 0) { + encoded.push(this.encodeStoryboardLayer(foreground)); + } + + encoded.push("//Storyboard Layer 4 (Overlay)"); + + const overlay = storyboard.getLayerByType(LayerType.Overlay); + + if (overlay.elements.length > 0) { + encoded.push(this.encodeStoryboardLayer(overlay)); + } + + return encoded.join("\n"); + } + static encodeStoryboardLayer(layer) { + const encoded = []; + + layer.elements.forEach((element) => { + let _a, _b, _c; + + encoded.push(this.encodeStoryboardElement(element, layer.name)); + + const elementWithCommands = element; + + (_a = + elementWithCommands === null || elementWithCommands === void 0 + ? void 0 + : elementWithCommands.loops) === null || _a === void 0 + ? void 0 + : _a.forEach((loop) => { + if (loop.commands.length > 0) { + encoded.push(this.encodeCompound(loop)); + encoded.push(this.encodeTimelineGroup(loop, 2)); + } + }); + + if ( + ((_b = + elementWithCommands === null || elementWithCommands === void 0 + ? void 0 + : elementWithCommands.timelineGroup) === null || _b === void 0 + ? void 0 + : _b.commands.length) > 0 + ) { + encoded.push( + this.encodeTimelineGroup(elementWithCommands.timelineGroup) + ); + } + + (_c = + elementWithCommands === null || elementWithCommands === void 0 + ? void 0 + : elementWithCommands.triggers) === null || _c === void 0 + ? void 0 + : _c.forEach((trigger) => { + if (trigger.commands.length > 0) { + encoded.push(this.encodeCompound(trigger)); + encoded.push(this.encodeTimelineGroup(trigger, 2)); + } + }); + }); + + return encoded.join("\n"); + } + static encodeStoryboardElement(element, layer) { + if (element instanceof StoryboardAnimation) { + return [ + "Animation", + layer, + Origins[element.origin], + `"${element.filePath}"`, + element.startPosition, + element.frameCount, + element.frameDelay, + element.loopType, + ].join(","); + } + + if (element instanceof StoryboardSprite) { + return [ + "Sprite", + layer, + Origins[element.origin], + `"${element.filePath}"`, + element.startPosition, + ].join(","); + } + + if (element instanceof StoryboardSample) { + return [ + "Sample", + element.startTime, + layer, + `"${element.filePath}"`, + element.volume, + ].join(","); + } + + if (element instanceof StoryboardVideo) { + return ["Video", element.startTime, element.filePath, "0,0"].join(","); + } + + return ""; + } + static encodeCompound(compound, depth = 1) { + const indentation = "".padStart(depth, " "); + + if (compound instanceof CommandLoop) { + return ( + indentation + + [compound.type, compound.loopStartTime, compound.totalIterations].join( + "," + ) + ); + } + + if (compound instanceof CommandTrigger) { + return ( + indentation + + [ + compound.type, + compound.triggerName, + compound.triggerStartTime, + compound.triggerEndTime, + compound.groupNumber, + ].join(",") + ); + } + + return ""; + } + static encodeTimelineGroup(timelineGroup, depth = 1) { + const indentation = "".padStart(depth, " "); + const encoded = []; + const commands = timelineGroup.commands; + let shouldSkip = false; + + for (let i = 0; i < commands.length; ++i) { + if (shouldSkip) { + shouldSkip = false; + continue; + } + + if (i < commands.length - 1) { + const current = commands[i]; + const next = commands[i + 1]; + const currentMoveX = current.type === CommandType.MovementX; + const nextMoveY = next.type === CommandType.MovementY; + const sameEasing = current.easing === next.easing; + const sameStartTime = current.startTime === next.startTime; + const sameEndTime = current.endTime === next.endTime; + const sameCommand = sameEasing && sameStartTime && sameEndTime; + + if (currentMoveX && nextMoveY && sameCommand) { + encoded.push(indentation + this.encodeMoveCommand(current, next)); + shouldSkip = true; + continue; + } + } + + encoded.push(indentation + this.encodeCommand(commands[i])); + } + + return encoded.join("\n"); + } + static encodeMoveCommand(moveX, moveY) { + const encoded = [ + CommandType.Movement, + moveX.easing, + moveX.startTime, + moveX.startTime !== moveX.endTime ? moveX.endTime : "", + moveX.startValue, + moveY.startValue, + ]; + const equalX = moveX.startValue === moveX.endValue; + const equalY = moveY.startValue === moveY.endValue; + + if (!equalX || !equalY) { + encoded.push(`${moveX.endValue},${moveY.endValue}`); + } + + return encoded.join(","); + } + static encodeCommand(command) { + const encoded = [ + command.type, + command.easing, + command.startTime, + command.startTime !== command.endTime ? command.endTime : "", + this._encodeCommandParams(command), + ]; + + return encoded.join(","); + } + static _encodeCommandParams(command) { + if (command.type === CommandType.Parameter) { + return command.parameter; + } + + if (command.type === CommandType.Color) { + const toRGB = (c) => `${c.red},${c.green},${c.blue}`; + const colorCommand = command; + const start = colorCommand.startValue; + const end = colorCommand.endValue; + + return this._areValuesEqual(command) + ? toRGB(start) + : toRGB(start) + "," + toRGB(end); + } + + return this._areValuesEqual(command) + ? `${command.startValue}` + : `${command.startValue},${command.endValue}`; + } + static _areValuesEqual(command) { + if (command.type === CommandType.VectorScale) { + const vectorCommand = command; + + return vectorCommand.startValue.equals(vectorCommand.endValue); + } + + if (command.type === CommandType.Color) { + const colorCommand = command; + + return colorCommand.startValue.equals(colorCommand.endValue); + } + + return command.startValue === command.endValue; + } +} + +class BeatmapEventEncoder { + static encodeEventSection(beatmap) { + const encoded = []; + const events = beatmap.events; + + encoded.push("[Events]"); + encoded.push("//Background and Video events"); + + if (events.backgroundPath) { + encoded.push(`0,0,"${events.backgroundPath}",0,0`); + } + + if (events.storyboard) { + encoded.push(StoryboardEventEncoder.encodeVideos(events.storyboard)); + } + + encoded.push("//Break Periods"); + + if (events.breaks && events.breaks.length > 0) { + events.breaks.forEach((b) => { + encoded.push( + `${EventType[EventType.Break]},${b.startTime},${b.endTime}` + ); + }); + } + + if (events.storyboard) { + encoded.push(StoryboardEventEncoder.encodeStoryboard(events.storyboard)); + } + + return encoded.join("\n"); + } +} + +class BeatmapGeneralEncoder { + static encodeGeneralSection(beatmap) { + const encoded = ["[General]"]; + const general = beatmap.general; + + encoded.push(`AudioFilename:${general.audioFilename}`); + encoded.push(`AudioLeadIn:${general.audioLeadIn}`); + + if (general.audioHash) { + encoded.push(`AudioHash:${general.audioHash}`); + } + + encoded.push(`PreviewTime:${general.previewTime}`); + encoded.push(`Countdown:${general.countdown}`); + encoded.push(`SampleSet:${SampleSet[general.sampleSet]}`); + encoded.push(`StackLeniency:${general.stackLeniency}`); + encoded.push(`Mode:${beatmap.mode}`); + encoded.push(`LetterboxInBreaks:${+general.letterboxInBreaks}`); + + if (general.storyFireInFront) { + encoded.push(`StoryFireInFront:${+general.storyFireInFront}`); + } + + encoded.push(`UseSkinSprites:${+general.useSkinSprites}`); + + if (general.alwaysShowPlayfield) { + encoded.push(`AlwaysShowPlayfield:${+general.alwaysShowPlayfield}`); + } + + encoded.push(`OverlayPosition:${general.overlayPosition}`); + encoded.push(`SkinPreference:${general.skinPreference}`); + encoded.push(`EpilepsyWarning:${+general.epilepsyWarning}`); + encoded.push(`CountdownOffset:${general.countdownOffset}`); + encoded.push(`SpecialStyle:${+general.specialStyle}`); + encoded.push(`WidescreenStoryboard:${+general.widescreenStoryboard}`); + encoded.push( + `SamplesMatchPlaybackRate:${+general.samplesMatchPlaybackRate}` + ); + + return encoded.join("\n"); + } +} + +class BeatmapHitObjectEncoder { + static encodeHitObjects(beatmap) { + const encoded = ["[HitObjects]"]; + const difficulty = beatmap.difficulty; + const hitObjects = beatmap.hitObjects; + + hitObjects.forEach((hitObject) => { + const general = []; + const position = hitObject.startPosition; + const startPosition = new Vector2( + position ? position.x : 256, + position ? position.y : 192 + ); + + if (beatmap.mode === 3) { + const totalColumns = Math.trunc(Math.max(1, difficulty.circleSize)); + const multiplier = Math.round((512 / totalColumns) * 100000) / 100000; + const column = hitObject.startX; + + startPosition.x = + Math.ceil(column * multiplier) + Math.trunc(multiplier / 2); + } + + general.push(startPosition.toString()); + general.push(hitObject.startTime.toString()); + general.push(hitObject.hitType.toString()); + general.push(hitObject.hitSound.toString()); + + const extras = []; + + if (hitObject.hitType & HitType.Slider) { + const slider = hitObject; + + extras.push(this.encodePathData(slider, startPosition)); + } else if (hitObject.hitType & HitType.Spinner) { + const spinner = hitObject; + + extras.push(this.encodeEndTimeData(spinner)); + } else if (hitObject.hitType & HitType.Hold) { + const hold = hitObject; + + extras.push(this.encodeEndTimeData(hold)); + } + + const set = []; + const normal = hitObject.samples.find( + (s) => s.hitSound === HitSound[HitSound.Normal] + ); + const addition = hitObject.samples.find( + (s) => s.hitSound !== HitSound[HitSound.Normal] + ); + let normalSet = SampleSet.None; + let additionSet = SampleSet.None; + + if (normal) { + normalSet = SampleSet[normal.sampleSet]; + } + + if (addition) { + additionSet = SampleSet[addition.sampleSet]; + } + + set[0] = normalSet.toString(); + set[1] = additionSet.toString(); + set[2] = hitObject.samples[0].customIndex.toString(); + set[3] = hitObject.samples[0].volume.toString(); + set[4] = hitObject.samples[0].filename; + extras.push(set.join(":")); + + const generalLine = general.join(","); + const extrasLine = + hitObject.hitType & HitType.Hold ? extras.join(":") : extras.join(","); + + encoded.push([generalLine, extrasLine].join(",")); + }); + + return encoded.join("\n"); + } + static encodePathData(slider, offset) { + const path = []; + let lastType; + + slider.path.controlPoints.forEach((point, i) => { + if (point.type !== null) { + let needsExplicitSegment = + point.type !== lastType || point.type === PathType.PerfectCurve; + + if (i > 1) { + const p1 = offset.add(slider.path.controlPoints[i - 1].position); + const p2 = offset.add(slider.path.controlPoints[i - 2].position); + + if (~~p1.x === ~~p2.x && ~~p1.y === ~~p2.y) { + needsExplicitSegment = true; + } + } + + if (needsExplicitSegment) { + path.push(slider.path.curveType); + lastType = point.type; + } else { + path.push( + `${offset.x + point.position.x}:${offset.y + point.position.y}` + ); + } + } + + if (i !== 0) { + path.push( + `${offset.x + point.position.x}:${offset.y + point.position.y}` + ); + } + }); + + const data = []; + + data.push(path.join("|")); + data.push((slider.repeats + 1).toString()); + data.push(slider.distance.toString()); + + const adds = []; + const sets = []; + + slider.nodeSamples.forEach((node, nodeIndex) => { + adds[nodeIndex] = HitSound.None; + sets[nodeIndex] = [SampleSet.None, SampleSet.None]; + node.forEach((sample, sampleIndex) => { + if (sampleIndex === 0) { + sets[nodeIndex][0] = SampleSet[sample.sampleSet]; + } else { + adds[nodeIndex] |= HitSound[sample.hitSound]; + sets[nodeIndex][1] = SampleSet[sample.sampleSet]; + } + }); + }); + + data.push(adds.join("|")); + data.push(sets.map((set) => set.join(":")).join("|")); + + return data.join(","); + } + static encodeEndTimeData(hitObject) { + return hitObject.endTime.toString(); + } +} + +class BeatmapMetadataEncoder { + static encodeMetadataSection(beatmap) { + const encoded = ["[Metadata]"]; + const metadata = beatmap.metadata; + + encoded.push(`Title:${metadata.title}`); + encoded.push(`TitleUnicode:${metadata.titleUnicode}`); + encoded.push(`Artist:${metadata.artist}`); + encoded.push(`ArtistUnicode:${metadata.artistUnicode}`); + encoded.push(`Creator:${metadata.creator}`); + encoded.push(`Version:${metadata.version}`); + encoded.push(`Source:${metadata.source}`); + encoded.push(`Tags:${metadata.tags.join(" ")}`); + encoded.push(`BeatmapID:${metadata.beatmapId}`); + encoded.push(`BeatmapSetID:${metadata.beatmapSetId}`); + + return encoded.join("\n"); + } +} + +class BeatmapTimingPointEncoder { + static encodeControlPoints(beatmap) { + const encoded = ["[TimingPoints]"]; + + beatmap.controlPoints.groups.forEach((group) => { + const points = group.controlPoints; + const timing = points.find((c) => c.beatLength); + + if (timing) { + encoded.push(this.encodeGroup(group, true)); + } + + encoded.push(this.encodeGroup(group)); + }); + + return encoded.join("\n"); + } + static encodeGroup(group, useTiming = false) { + const { difficultyPoint, effectPoint, samplePoint, timingPoint } = + this.updateActualPoints(group); + const startTime = group.startTime; + let beatLength = -100; + + if (difficultyPoint !== null) { + beatLength /= difficultyPoint.sliderVelocity; + } + + let sampleSet = SampleSet.None; + let customIndex = 0; + let volume = 100; + + if (samplePoint !== null) { + sampleSet = SampleSet[samplePoint.sampleSet]; + customIndex = samplePoint.customIndex; + volume = samplePoint.volume; + } + + let effects = EffectType.None; + + if (effectPoint !== null) { + const kiai = effectPoint.kiai ? EffectType.Kiai : EffectType.None; + const omitFirstBarLine = effectPoint.omitFirstBarLine + ? EffectType.OmitFirstBarLine + : EffectType.None; + + effects |= kiai | omitFirstBarLine; + } + + let timeSignature = TimeSignature.SimpleQuadruple; + let uninherited = 0; + + if (useTiming && timingPoint !== null) { + beatLength = timingPoint.beatLength; + timeSignature = timingPoint.timeSignature; + uninherited = 1; + } + + return [ + startTime, + beatLength, + timeSignature, + sampleSet, + customIndex, + volume, + uninherited, + effects, + ].join(","); + } + static updateActualPoints(group) { + let timingPoint = null; + + group.controlPoints.forEach((point) => { + if ( + point.pointType === ControlPointType.DifficultyPoint && + !point.isRedundant(this.lastDifficultyPoint) + ) { + this.lastDifficultyPoint = point; + } + + if ( + point.pointType === ControlPointType.EffectPoint && + !point.isRedundant(this.lastEffectPoint) + ) { + this.lastEffectPoint = point; + } + + if ( + point.pointType === ControlPointType.SamplePoint && + !point.isRedundant(this.lastSamplePoint) + ) { + this.lastSamplePoint = point; + } + + if (point.pointType === ControlPointType.TimingPoint) { + timingPoint = point; + } + }); + + return { + timingPoint, + difficultyPoint: this.lastDifficultyPoint, + effectPoint: this.lastEffectPoint, + samplePoint: this.lastSamplePoint, + }; + } +} +BeatmapTimingPointEncoder.lastDifficultyPoint = null; +BeatmapTimingPointEncoder.lastEffectPoint = null; +BeatmapTimingPointEncoder.lastSamplePoint = null; + +class ReplayEncoder { + static encodeLifeBar(frames) { + if (!frames.length) { + return ""; + } + + return frames.map((f) => `${f.startTime}|${f.health}`).join(","); + } + static encodeReplayFrames(frames, beatmap) { + const encoded = []; + + if (frames) { + let lastTime = 0; + + frames.forEach((frame) => { + let _a, _b, _c; + const time = Math.round(frame.startTime); + const legacyFrame = this._getLegacyFrame(frame, beatmap); + const encodedData = [ + time - lastTime, + (_a = + legacyFrame === null || legacyFrame === void 0 + ? void 0 + : legacyFrame.mouseX) !== null && _a !== void 0 + ? _a + : 0, + (_b = + legacyFrame === null || legacyFrame === void 0 + ? void 0 + : legacyFrame.mouseY) !== null && _b !== void 0 + ? _b + : 0, + (_c = + legacyFrame === null || legacyFrame === void 0 + ? void 0 + : legacyFrame.buttonState) !== null && _c !== void 0 + ? _c + : ReplayButtonState.None, + ]; + + encoded.push(encodedData.join("|")); + lastTime = time; + }); + } + + encoded.push("-12345|0|0|0"); + + return encoded.join(","); + } + static _getLegacyFrame(frame, beatmap) { + if (frame instanceof LegacyReplayFrame) { + return frame; + } + + const convertibleFrame = frame; + + if (convertibleFrame.toLegacy) { + return convertibleFrame.toLegacy(beatmap); + } + + throw new Error( + "Some of the replay frames can not be converted to the legacy format!" + ); + } +} + +const textDecoder = new TextDecoder(); + +function concatBufferViews(list) { + if (list.length <= 0) { + return new Uint8Array(0); + } + + const bufferLength = list.reduce((len, buf) => len + buf.byteLength, 0); + const arrayBuffer = new Uint8Array(bufferLength); + + list.reduce((offset, view) => { + arrayBuffer.set(new Uint8Array(view.buffer), offset); + + return offset + view.byteLength; + }, 0); + + return arrayBuffer; +} + +function stringifyBuffer(data) { + if (typeof data === "string") { + return data; + } + + return textDecoder.decode(data); +} + +class SerializationWriter { + constructor() { + this._bytesWritten = 0; + this._views = []; + } + get bytesWritten() { + return this._bytesWritten; + } + finish() { + return concatBufferViews(this._views); + } + writeByte(value) { + return this._update(1, new Uint8Array([value])); + } + writeBytes(value) { + this._bytesWritten += value.byteLength; + this._views.push(value); + + return value.byteLength; + } + writeShort(value) { + return this._update(2, new Uint16Array([value])); + } + writeInteger(value) { + return this._update(4, new Int32Array([value])); + } + writeLong(value) { + return this._update(8, new BigInt64Array([value])); + } + writeDate(date) { + const epochTicks = BigInt(62135596800000); + const ticks = BigInt(date.getTime()); + + return this.writeLong((ticks + epochTicks) * BigInt(1e4)); + } + writeString(value) { + if (value.length === 0) { + return this.writeByte(0x00); + } + + let bytesWritten = this.writeByte(0x0b); + + bytesWritten += this.writeULEB128(value.length); + + const view = new Uint8Array(value.length); + + for (let i = 0; i < value.length; ++i) { + view[i] = value.charCodeAt(i); + bytesWritten++; + } + + this._update(bytesWritten, view); + + return bytesWritten; + } + writeULEB128(value) { + let byte = 0; + let bytesWritten = 0; + + do { + byte = value & 0x7f; + value >>= 7; + + if (value !== 0) { + byte |= 0x80; + } + + bytesWritten += this.writeByte(byte); + } while (value !== 0); + + return bytesWritten; + } + _update(bytesWritten, buffer) { + this._bytesWritten += bytesWritten; + this._views.push(buffer); + + return bytesWritten; + } +} + +class BeatmapEncoder { + async encodeToPath(path, beatmap) { + if (!path.endsWith(FileFormat.Beatmap)) { + path += FileFormat.Beatmap; + } + + try { + await browserFSOperation(browserFSOperation(path), { recursive: true }); + await browserFSOperation(path, await this.encodeToString(beatmap)); + } catch (err) { + const reason = err.message || err; + throw new Error(`Failed to encode a beatmap: ${reason}`); + } + } + encodeToString(beatmap) { + let _a; + + if ( + !(beatmap === null || beatmap === void 0 ? void 0 : beatmap.fileFormat) + ) { + return ""; + } + + const fileFormat = + (_a = beatmap.fileFormat) !== null && _a !== void 0 + ? _a + : BeatmapEncoder.FIRST_LAZER_VERSION; + const encoded = [ + `osu file format v${fileFormat}`, + BeatmapGeneralEncoder.encodeGeneralSection(beatmap), + BeatmapEditorEncoder.encodeEditorSection(beatmap), + BeatmapMetadataEncoder.encodeMetadataSection(beatmap), + BeatmapDifficultyEncoder.encodeDifficultySection(beatmap), + BeatmapEventEncoder.encodeEventSection(beatmap), + BeatmapTimingPointEncoder.encodeControlPoints(beatmap), + BeatmapColorEncoder.encodeColors(beatmap), + BeatmapHitObjectEncoder.encodeHitObjects(beatmap), + ]; + + return encoded.join("\n\n") + "\n"; + } +} +BeatmapEncoder.FIRST_LAZER_VERSION = 128; + +class StoryboardEncoder { + async encodeToPath(path, storyboard) { + if (!path.endsWith(FileFormat.Storyboard)) { + path += FileFormat.Storyboard; + } + + try { + await browserFSOperation(browserFSOperation(path), { recursive: true }); + await browserFSOperation(path, await this.encodeToString(storyboard)); + } catch (err) { + const reason = err.message || err; + throw new Error(`Failed to encode a storyboard: ${reason}`); + } + } + encodeToString(storyboard) { + if (!(storyboard instanceof Storyboard)) { + return ""; + } + + const encoded = [ + `osu file format v${storyboard.fileFormat}`, + StoryboardEventEncoder.encodeEventSection(storyboard), + ]; + + return encoded.join("\n\n") + "\n"; + } +} + +class LZMA { + static async decompress(data) { + try { + return await this._lzma.decompress(data); + } catch { + return ""; + } + } + static async compress(data) { + try { + return await this._lzma.compress(data, 1); + } catch { + return new Uint8Array([]); + } + } +} +LZMA._lzma = getLZMAInstance(); + +function getLZMAInstance() { + return { + decompress(data) { + return new Promise((res, rej) => { + decompress(data, (result, err) => { + err + ? rej(err) + : res( + typeof result === "string" + ? result + : new Uint8Array(result).toString() + ); + }); + }); + }, + compress(data) { + return new Promise((res, rej) => { + compress(data, 1, (result, err) => { + err ? rej(err) : res(new Uint8Array(result)); + }); + }); + }, + }; +} + +class ScoreEncoder { + async encodeToPath(path, score, beatmap) { + if (!path.endsWith(FileFormat.Replay)) { + path += FileFormat.Replay; + } + + const data = await this.encodeToBuffer(score, beatmap); + + try { + await browserFSOperation(browserFSOperation(path), { recursive: true }); + await browserFSOperation(path, new Uint8Array(data)); + } catch (err) { + const reason = err.message || err; + throw new Error(`Failed to encode a score: ${reason}`); + } + } + async encodeToBuffer(score, beatmap) { + let _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; + + if ( + typeof ((_a = + score === null || score === void 0 ? void 0 : score.info) === null || + _a === void 0 + ? void 0 + : _a.id) !== "number" + ) { + return new Uint8Array(); + } + + const writer = new SerializationWriter(); + + try { + writer.writeByte(score.info.rulesetId); + writer.writeInteger( + (_c = + (_b = score.replay) === null || _b === void 0 + ? void 0 + : _b.gameVersion) !== null && _c !== void 0 + ? _c + : ScoreEncoder.DEFAULT_GAME_VERSION + ); + writer.writeString( + (_d = score.info.beatmapHashMD5) !== null && _d !== void 0 ? _d : "" + ); + writer.writeString(score.info.username); + writer.writeString( + (_f = + (_e = score.replay) === null || _e === void 0 + ? void 0 + : _e.hashMD5) !== null && _f !== void 0 + ? _f + : "" + ); + writer.writeShort(score.info.count300); + writer.writeShort(score.info.count100); + writer.writeShort(score.info.count50); + writer.writeShort(score.info.countGeki); + writer.writeShort(score.info.countKatu); + writer.writeShort(score.info.countMiss); + writer.writeInteger(score.info.totalScore); + writer.writeShort(score.info.maxCombo); + writer.writeByte(Number(score.info.perfect)); + writer.writeInteger( + ((_h = + (_g = score.info.mods) === null || _g === void 0 + ? void 0 + : _g.bitwise) !== null && _h !== void 0 + ? _h + : Number(score.info.rawMods)) || 0 + ); + writer.writeString( + ReplayEncoder.encodeLifeBar( + (_k = + (_j = score.replay) === null || _j === void 0 + ? void 0 + : _j.lifeBar) !== null && _k !== void 0 + ? _k + : [] + ) + ); + writer.writeDate(score.info.date); + + if (score.replay) { + const replayData = ReplayEncoder.encodeReplayFrames( + score.replay.frames, + beatmap + ); + const encodedData = await LZMA.compress(replayData); + + writer.writeInteger(encodedData.byteLength); + writer.writeBytes(encodedData); + } else { + writer.writeInteger(0); + } + + writer.writeLong(BigInt(score.info.id)); + + return writer.finish(); + } catch (err) { + const reason = err.message || err; + throw new Error(`Failed to encode a score: '${reason}'`); + } + } +} +ScoreEncoder.DEFAULT_GAME_VERSION = 20230621; + +class BeatmapHitObjectDecoder { + static handleLine(line, beatmap, offset) { + const data = line.split(",").map((v) => v.trim()); + const hitType = Parsing.parseInt(data[3]); + const hitObject = this.createHitObject(hitType); + + hitObject.startX = Parsing.parseInt(data[0], Parsing.MAX_COORDINATE_VALUE); + hitObject.startY = Parsing.parseInt(data[1], Parsing.MAX_COORDINATE_VALUE); + hitObject.startTime = Parsing.parseFloat(data[2]) + offset; + hitObject.hitType = hitType; + hitObject.hitSound = Parsing.parseInt(data[4]); + + const bankInfo = new SampleBank(); + + this.addExtras( + data.slice(5), + hitObject, + bankInfo, + offset, + beatmap.fileFormat + ); + this.addComboOffset(hitObject, beatmap); + + if (hitObject.samples.length === 0) { + hitObject.samples = this.convertSoundType(hitObject.hitSound, bankInfo); + } + + beatmap.hitObjects.push(hitObject); + } + static addComboOffset(hitObject, beatmap) { + const isStandard = beatmap.originalMode === 0; + const isCatch = beatmap.originalMode === 2; + + if (!isStandard && !isCatch) { + return; + } + + const comboObject = hitObject; + const comboOffset = Math.trunc( + (hitObject.hitType & HitType.ComboOffset) >> 4 + ); + const newCombo = !!(hitObject.hitType & HitType.NewCombo); + + if ( + hitObject.hitType & HitType.Normal || + hitObject.hitType & HitType.Slider + ) { + comboObject.isNewCombo = newCombo || this._forceNewCombo; + comboObject.comboOffset = comboOffset + this._extraComboOffset; + this._forceNewCombo = false; + this._extraComboOffset = 0; + } + + if (hitObject.hitType & HitType.Spinner) { + this._forceNewCombo = beatmap.fileFormat <= 8 || newCombo || false; + this._extraComboOffset += comboOffset; + } + } + static addExtras(data, hitObject, bankInfo, offset, fileFormat) { + if (hitObject.hitType & HitType.Normal && data.length > 0) { + this.readCustomSampleBanks(data[0], bankInfo); + } + + if (hitObject.hitType & HitType.Slider) { + return this.addSliderExtras(data, hitObject, bankInfo, fileFormat); + } + + if (hitObject.hitType & HitType.Spinner) { + return this.addSpinnerExtras(data, hitObject, bankInfo, offset); + } + + if (hitObject.hitType & HitType.Hold) { + return this.addHoldExtras(data, hitObject, bankInfo, offset); + } + } + static addSliderExtras(extras, slider, bankInfo, fileFormat) { + const pathString = extras[0]; + const offset = slider.startPosition; + const repeats = Parsing.parseInt(extras[1]); + + if (slider.repeats > 9000) { + throw new Error("Repeat count is way too high"); + } + + slider.repeats = Math.max(0, repeats - 1); + slider.path.controlPoints = this.convertPathString( + pathString, + offset, + fileFormat + ); + slider.path.curveType = slider.path.controlPoints[0].type; + + if (extras.length > 2) { + const length = Parsing.parseFloat( + extras[2], + Parsing.MAX_COORDINATE_VALUE + ); + + slider.path.expectedDistance = Math.max(0, length); + } + + if (extras.length > 5) { + this.readCustomSampleBanks(extras[5], bankInfo); + } + + slider.samples = this.convertSoundType(slider.hitSound, bankInfo); + slider.nodeSamples = this.getSliderNodeSamples(extras, slider, bankInfo); + } + static addSpinnerExtras(extras, spinner, bankInfo, offset) { + spinner.endTime = Parsing.parseInt(extras[0]) + offset; + + if (extras.length > 1) { + this.readCustomSampleBanks(extras[1], bankInfo); + } + } + static addHoldExtras(extras, hold, bankInfo, offset) { + hold.endTime = hold.startTime; + + if (extras.length > 0 && extras[0]) { + const ss = extras[0].split(":"); + + hold.endTime = Math.max(hold.endTime, Parsing.parseFloat(ss[0])) + offset; + this.readCustomSampleBanks(ss.slice(1).join(":"), bankInfo); + } + } + static getSliderNodeSamples(extras, slider, bankInfo) { + const nodes = slider.repeats + 2; + const nodeBankInfos = []; + + for (let i = 0; i < nodes; ++i) { + nodeBankInfos.push(bankInfo.clone()); + } + + if (extras.length > 4 && extras[4].length > 0) { + const sets = extras[4].split("|"); + + for (let i = 0; i < nodes; ++i) { + if (i >= sets.length) { + break; + } + + this.readCustomSampleBanks(sets[i], nodeBankInfos[i]); + } + } + + const nodeSoundTypes = []; + + for (let i = 0; i < nodes; ++i) { + nodeSoundTypes.push(slider.hitSound); + } + + if (extras.length > 3 && extras[3].length > 0) { + const adds = extras[3].split("|"); + + for (let i = 0; i < nodes; ++i) { + if (i >= adds.length) { + break; + } + + nodeSoundTypes[i] = parseInt(adds[i]) || HitSound.None; + } + } + + const nodeSamples = []; + + for (let i = 0; i < nodes; i++) { + nodeSamples.push( + this.convertSoundType(nodeSoundTypes[i], nodeBankInfos[i]) + ); + } + + return nodeSamples; + } + static convertPathString(pathString, offset, fileFormat) { + const pathSplit = pathString.split("|").map((p) => p.trim()); + const controlPoints = []; + let startIndex = 0; + let endIndex = 0; + let isFirst = true; + + while (++endIndex < pathSplit.length) { + if (pathSplit[endIndex].length > 1) { + continue; + } + + const points = pathSplit.slice(startIndex, endIndex); + const endPoint = + endIndex < pathSplit.length - 1 ? pathSplit[endIndex + 1] : null; + const convertedPoints = this.convertPoints( + points, + endPoint, + isFirst, + offset, + fileFormat + ); + + for (const point of convertedPoints) { + controlPoints.push(...point); + } + + startIndex = endIndex; + isFirst = false; + } + + if (endIndex > startIndex) { + const points = pathSplit.slice(startIndex, endIndex); + const convertedPoints = this.convertPoints( + points, + null, + isFirst, + offset, + fileFormat + ); + + for (const point of convertedPoints) { + controlPoints.push(...point); + } + } + + return controlPoints; + } + static *convertPoints(points, endPoint, isFirst, offset, fileFormat) { + const readOffset = isFirst ? 1 : 0; + const endPointLength = endPoint !== null ? 1 : 0; + const vertices = []; + + if (readOffset === 1) { + vertices[0] = new PathPoint(); + } + + for (let i = 1; i < points.length; ++i) { + vertices[readOffset + i - 1] = readPoint(points[i], offset); + } + + if (endPoint !== null) { + vertices[vertices.length - 1] = readPoint(endPoint, offset); + } + + let type = this.convertPathType(points[0]); + + if (type === PathType.PerfectCurve) { + if (vertices.length !== 3) { + type = PathType.Bezier; + } else if (isLinear(vertices)) { + type = PathType.Linear; + } + } + + vertices[0].type = type; + + let startIndex = 0; + let endIndex = 0; + + while (++endIndex < vertices.length - endPointLength) { + if ( + !vertices[endIndex].position.equals(vertices[endIndex - 1].position) + ) { + continue; + } + + const isStableBeatmap = fileFormat < BeatmapEncoder.FIRST_LAZER_VERSION; + + if (type === PathType.Catmull && endIndex > 1 && isStableBeatmap) { + continue; + } + + if (endIndex === vertices.length - endPointLength - 1) { + continue; + } + + vertices[endIndex - 1].type = type; + yield vertices.slice(startIndex, endIndex); + startIndex = endIndex + 1; + } + + if (endIndex > startIndex) { + yield vertices.slice(startIndex, endIndex); + } + + function readPoint(point, offset) { + const coords = point.split(":").map((v) => { + return Math.trunc(Parsing.parseFloat(v, Parsing.MAX_COORDINATE_VALUE)); + }); + const pos = new Vector2(coords[0], coords[1]).fsubtract(offset); + + return new PathPoint(pos); + } + + function isLinear(p) { + const yx = + (p[1].position.y - p[0].position.y) * + (p[2].position.x - p[0].position.x); + const xy = + (p[1].position.x - p[0].position.x) * + (p[2].position.y - p[0].position.y); + const acceptableDifference = 0.001; + + return Math.abs(yx - xy) < acceptableDifference; + } + } + static convertPathType(type) { + switch (type) { + default: + case "C": + return PathType.Catmull; + case "B": + return PathType.Bezier; + case "L": + return PathType.Linear; + case "P": + return PathType.PerfectCurve; + } + } + static readCustomSampleBanks(hitSample, bankInfo) { + if (!hitSample) { + return; + } + + const split = hitSample.split(":"); + + bankInfo.normalSet = Parsing.parseInt(split[0]); + bankInfo.additionSet = Parsing.parseInt(split[1]); + + if (bankInfo.additionSet === SampleSet.None) { + bankInfo.additionSet = bankInfo.normalSet; + } + + if (split.length > 2) { + bankInfo.customIndex = Parsing.parseInt(split[2]); + } + + if (split.length > 3) { + bankInfo.volume = Math.max(0, Parsing.parseInt(split[3])); + } + + bankInfo.filename = split.length > 4 ? split[4] : ""; + } + static convertSoundType(type, bankInfo) { + if (bankInfo.filename) { + const sample = new HitSample(); + + sample.filename = bankInfo.filename; + sample.volume = bankInfo.volume; + + return [sample]; + } + + const soundTypes = [new HitSample()]; + + soundTypes[0].hitSound = HitSound[HitSound.Normal]; + soundTypes[0].sampleSet = SampleSet[bankInfo.normalSet]; + soundTypes[0].isLayered = + type !== HitSound.None && !(type & HitSound.Normal); + + if (type & HitSound.Finish) { + const sample = new HitSample(); + + sample.hitSound = HitSound[HitSound.Finish]; + soundTypes.push(sample); + } + + if (type & HitSound.Whistle) { + const sample = new HitSample(); + + sample.hitSound = HitSound[HitSound.Whistle]; + soundTypes.push(sample); + } + + if (type & HitSound.Clap) { + const sample = new HitSample(); + + sample.hitSound = HitSound[HitSound.Clap]; + soundTypes.push(sample); + } + + soundTypes.forEach((sound, i) => { + sound.sampleSet = + i !== 0 + ? SampleSet[bankInfo.additionSet] + : SampleSet[bankInfo.normalSet]; + + sound.volume = bankInfo.volume; + sound.customIndex = 0; + + if (bankInfo.customIndex >= 2) { + sound.customIndex = bankInfo.customIndex; + } + }); + + return soundTypes; + } + static createHitObject(hitType) { + if (hitType & HitType.Normal) { + return new HittableObject(); + } + + if (hitType & HitType.Slider) { + return new SlidableObject(); + } + + if (hitType & HitType.Spinner) { + return new SpinnableObject(); + } + + if (hitType & HitType.Hold) { + return new HoldableObject(); + } + + throw new Error(`Unknown hit object type: ${hitType}!`); + } +} +BeatmapHitObjectDecoder._forceNewCombo = false; +BeatmapHitObjectDecoder._extraComboOffset = 0; + +class BeatmapMetadataDecoder { + static handleLine(line, beatmap) { + const [key, ...values] = line.split(":"); + const value = values.join(":").trim(); + + switch (key.trim()) { + case "Title": + beatmap.metadata.title = value; + break; + case "TitleUnicode": + beatmap.metadata.titleUnicode = value; + break; + case "Artist": + beatmap.metadata.artist = value; + break; + case "ArtistUnicode": + beatmap.metadata.artistUnicode = value; + break; + case "Creator": + beatmap.metadata.creator = value; + break; + case "Version": + beatmap.metadata.version = value; + break; + case "Source": + beatmap.metadata.source = value; + break; + case "Tags": + beatmap.metadata.tags = value.split(" "); + break; + case "BeatmapID": + beatmap.metadata.beatmapId = Parsing.parseInt(value); + break; + case "BeatmapSetID": + beatmap.metadata.beatmapSetId = Parsing.parseInt(value); + } + } +} + +class BeatmapTimingPointDecoder { + static handleLine(line, beatmap, offset) { + this.controlPoints = beatmap.controlPoints; + + const data = line.split(","); + let timeSignature = TimeSignature.SimpleQuadruple; + let sampleSet = SampleSet[SampleSet.None]; + let customIndex = 0; + let volume = 100; + let timingChange = true; + let effects = EffectType.None; + + if (data.length > 2) { + switch (data.length) { + default: + case 8: + effects = Parsing.parseInt(data[7]); + case 7: + timingChange = data[6] === "1"; + case 6: + volume = Parsing.parseInt(data[5]); + case 5: + customIndex = Parsing.parseInt(data[4]); + case 4: + sampleSet = SampleSet[Parsing.parseInt(data[3])]; + case 3: + timeSignature = Parsing.parseInt(data[2]); + } + } + + if (timeSignature < 1) { + throw new Error("The numerator of a time signature must be positive."); + } + + const startTime = Parsing.parseFloat(data[0]) + offset; + const beatLength = Parsing.parseFloat( + data[1], + Parsing.MAX_PARSE_VALUE, + true + ); + let bpmMultiplier = 1; + let speedMultiplier = 1; + + if (beatLength < 0) { + speedMultiplier = 100 / -beatLength; + bpmMultiplier = Math.min(Math.fround(-beatLength), 10000); + bpmMultiplier = Math.max(10, bpmMultiplier) / 100; + } + + if (timingChange && Number.isNaN(beatLength)) { + throw new Error("Beat length cannot be NaN in a timing control point"); + } + + if (timingChange) { + const timingPoint = new TimingPoint(); + + timingPoint.beatLength = beatLength; + timingPoint.timeSignature = timeSignature; + this.addControlPoint(timingPoint, startTime, true); + } + + const difficultyPoint = new DifficultyPoint(); + + difficultyPoint.bpmMultiplier = bpmMultiplier; + difficultyPoint.sliderVelocity = speedMultiplier; + difficultyPoint.generateTicks = !Number.isNaN(beatLength); + difficultyPoint.isLegacy = true; + this.addControlPoint(difficultyPoint, startTime, timingChange); + + const effectPoint = new EffectPoint(); + + effectPoint.kiai = (effects & EffectType.Kiai) > 0; + effectPoint.omitFirstBarLine = (effects & EffectType.OmitFirstBarLine) > 0; + + if (beatmap.originalMode === 1 || beatmap.originalMode === 3) { + effectPoint.scrollSpeed = speedMultiplier; + } + + this.addControlPoint(effectPoint, startTime, timingChange); + + const samplePoint = new SamplePoint(); + + samplePoint.sampleSet = sampleSet; + samplePoint.customIndex = customIndex; + samplePoint.volume = volume; + this.addControlPoint(samplePoint, startTime, timingChange); + } + static addControlPoint(point, time, timingChange) { + if (time !== this.pendingTime) { + this.flushPendingPoints(); + } + + timingChange + ? this.pendingPoints.unshift(point) + : this.pendingPoints.push(point); + + this.pendingTime = time; + } + static flushPendingPoints() { + const pendingTime = this.pendingTime; + const pendingPoints = this.pendingPoints; + const controlPoints = this.controlPoints; + const pendingTypes = this.pendingTypes; + let i = pendingPoints.length; + + while (--i >= 0) { + if (pendingTypes.includes(pendingPoints[i].pointType)) { + continue; + } + + pendingTypes.push(pendingPoints[i].pointType); + controlPoints.add(pendingPoints[i], pendingTime); + } + + this.pendingPoints = []; + this.pendingTypes = []; + } +} +BeatmapTimingPointDecoder.pendingTime = 0; +BeatmapTimingPointDecoder.pendingTypes = []; +BeatmapTimingPointDecoder.pendingPoints = []; + +class ReplayDecoder { + static decodeLifeBar(data) { + if (!data) { + return []; + } + + const lifeBarFrames = []; + const frames = data.split(","); + + for (let i = 0; i < frames.length; ++i) { + if (!frames[i]) { + continue; + } + + const frameData = frames[i].split("|"); + + if (frameData.length < 2) { + continue; + } + + const frame = this.handleLifeBarFrame(frameData); + + lifeBarFrames.push(frame); + } + + return lifeBarFrames; + } + static handleLifeBarFrame(frameData) { + return new LifeBarFrame( + Parsing.parseInt(frameData[0]), + Parsing.parseFloat(frameData[1]) + ); + } + static decodeReplayFrames(data) { + if (!data) { + return []; + } + + let lastTime = 0; + const replayFrames = []; + const frames = data.split(","); + + for (let i = 0; i < frames.length; ++i) { + if (!frames[i]) { + continue; + } + + const frameData = frames[i].split("|"); + + if (frameData.length < 4) { + continue; + } + + if (frameData[0] === "-12345") { + continue; + } + + const replayFrame = this.handleReplayFrame(frameData); + + lastTime += replayFrame.interval; + + if (i < 2 && replayFrame.mouseX === 256 && replayFrame.mouseY === -500) { + continue; + } + + if (replayFrame.interval < 0) { + continue; + } + + replayFrame.startTime = lastTime; + replayFrames.push(replayFrame); + } + + return replayFrames; + } + static handleReplayFrame(frameData) { + return new LegacyReplayFrame( + 0.0, + Parsing.parseFloat(frameData[0]), + new Vector2( + Parsing.parseFloat(frameData[1], Parsing.MAX_COORDINATE_VALUE), + Parsing.parseFloat(frameData[2], Parsing.MAX_COORDINATE_VALUE) + ), + Parsing.parseInt(frameData[3]) + ); + } +} + +class SerializationReader { + constructor(buffer) { + this._bytesRead = 0; + this.view = new DataView(new Uint8Array(buffer).buffer); + } + get bytesRead() { + return this._bytesRead; + } + get remainingBytes() { + return this.view.byteLength - this._bytesRead; + } + readByte() { + return this.view.getUint8(this._bytesRead++); + } + readBytes(length) { + const bytes = this.view.buffer.slice( + this._bytesRead, + this._bytesRead + length + ); + + this._bytesRead += length; + + return new Uint8Array(bytes); + } + readShort() { + const value = this.view.getUint16(this._bytesRead, true); + + this._bytesRead += 2; + + return value; + } + readInteger() { + const value = this.view.getInt32(this._bytesRead, true); + + this._bytesRead += 4; + + return value; + } + readLong() { + const value = this.view.getBigInt64(this._bytesRead, true); + + this._bytesRead += 8; + + return value; + } + readDate() { + const epochTicks = 62135596800000; + + return new Date(Number(this.readLong() / BigInt(1e4)) - epochTicks); + } + readULEB128() { + let val = 0; + let shift = 0; + let byte = 0; + + do { + byte = this.readByte(); + val |= (byte & 0x7f) << shift; + shift += 7; + } while ((byte & 0x80) !== 0); + + return val; + } + readString() { + if (this.readByte() !== 0x0b) { + return ""; + } + + const length = this.readULEB128(); + + return length > 0 ? stringifyBuffer(this.readBytes(length)) : ""; + } +} + +class StoryboardGeneralDecoder { + static handleLine(line, storyboard) { + const [key, ...values] = line.split(":").map((v) => v.trim()); + const value = values.join(" "); + + switch (key) { + case "UseSkinSprites": + storyboard.useSkinSprites = value === "1"; + } + } +} + +class StoryboardVariableDecoder { + static handleLine(line, variables) { + if (!line.startsWith("$")) { + return; + } + + const pair = line.split("="); + + if (pair.length === 2) { + variables.set(pair[0], pair[1].trimEnd()); + } + } + static decodeVariables(line, variables) { + if (!line.includes("$") || !variables.size) { + return line; + } + + variables.forEach((value, key) => { + line = line.replace(key, value); + }); + + return line; + } +} + +class Decoder { + async _getFileBuffer(path) { + try { + await browserFSOperation(path); + } catch { + throw new Error("File doesn't exist!"); + } + + try { + return await browserFSOperation(path); + } catch { + throw new Error("File can't be read!"); + } + } + async _getFileUpdateDate(path) { + try { + return (await browserFSOperation(path)).mtime; + } catch { + throw new Error("Failed to get last file update date!"); + } + } +} + +class SectionMap extends Map { + constructor() { + super(...arguments); + this.currentSection = null; + } + get(section) { + let _a; + + return (_a = super.get(section)) !== null && _a !== void 0 ? _a : false; + } + set(section, state = true) { + return super.set(section, state); + } + reset() { + this.forEach((_, key, map) => { + map.set(key, true); + }); + + this.currentSection = null; + + return this; + } + get hasEnabledSections() { + for (const state of this.values()) { + if (state) { + return true; + } + } + + return false; + } + get isSectionEnabled() { + return this.currentSection ? this.get(this.currentSection) : false; + } +} + +class SectionDecoder extends Decoder { + constructor() { + super(...arguments); + this._lines = null; + this._sectionMap = new SectionMap(); + } + _getLines(data) { + let lines = null; + + if (data.constructor === Array) { + lines = data; + } + + if (!lines || !lines.length) { + throw new Error("Data not found!"); + } + + return lines; + } + _parseLine(line, output) { + if (this._shouldSkipLine(line)) { + return LineType.Empty; + } + + line = this._preprocessLine(line); + + if (line.includes("osu file format v")) { + return LineType.FileFormat; + } + + if (line.startsWith("[") && line.endsWith("]")) { + const section = line.slice(1, -1); + + if (this._sectionMap.currentSection) { + this._sectionMap.set(this._sectionMap.currentSection, false); + this._sectionMap.currentSection = null; + } + + if (!this._sectionMap.hasEnabledSections) { + return LineType.Break; + } + + if (section in Section) { + this._sectionMap.currentSection = section; + } + + return LineType.Section; + } + + if (!this._sectionMap.isSectionEnabled) { + return LineType.Empty; + } + + try { + this._parseSectionData(line, output); + + return LineType.Data; + } catch { + return LineType.Empty; + } + } + _parseSectionData(line, output) { + const outputWithColors = output; + + if (this._sectionMap.currentSection !== Section.Colours) { + return; + } + + if ( + !(outputWithColors === null || outputWithColors === void 0 + ? void 0 + : outputWithColors.colors) + ) { + return; + } + + BeatmapColorDecoder.handleLine(line, outputWithColors); + } + _preprocessLine(line) { + if (this._sectionMap.currentSection !== Section.Metadata) { + line = this._stripComments(line); + } + + return line.trimEnd(); + } + _shouldSkipLine(line) { + return typeof line !== "string" || !line || line.startsWith("//"); + } + _stripComments(line) { + const index = line.indexOf("//"); + + return index > 0 ? line.substring(0, index) : line; + } + _reset() { + this._sectionMap.reset(); + this._lines = null; + } + _setEnabledSections(options) { + this._sectionMap.set( + Section.Colours, + options === null || options === void 0 ? void 0 : options.parseColours + ); + } +} + +class StoryboardDecoder extends SectionDecoder { + constructor() { + super(...arguments); + this._variables = new Map(); + } + async decodeFromPath(firstPath, secondPath) { + if ( + !firstPath.endsWith(FileFormat.Beatmap) && + !firstPath.endsWith(FileFormat.Storyboard) + ) { + throw new Error( + `Wrong format of the first file! Only ${FileFormat.Beatmap} and ${FileFormat.Storyboard} files are supported!` + ); + } + + if (typeof secondPath === "string") { + if (!secondPath.endsWith(FileFormat.Storyboard)) { + throw new Error( + `Wrong format of the second file! Only ${FileFormat.Storyboard} files are supported as a second argument!` + ); + } + } + + try { + const firstData = await this._getFileBuffer(firstPath); + const secondData = + typeof secondPath === "string" + ? await this._getFileBuffer(firstPath) + : undefined; + + return this.decodeFromBuffer(firstData, secondData); + } catch (err) { + const reason = err.message || err; + throw new Error(`Failed to decode a storyboard: '${reason}'`); + } + } + decodeFromBuffer(firstBuffer, secondBuffer) { + const firstString = stringifyBuffer(firstBuffer); + const secondString = secondBuffer + ? stringifyBuffer(secondBuffer) + : undefined; + + return this.decodeFromString(firstString, secondString); + } + decodeFromString(firstString, secondString) { + if (typeof firstString !== "string") { + firstString = String(firstString); + } + + if ( + typeof secondString !== "string" && + typeof secondString !== "undefined" + ) { + secondString = String(secondString); + } + + const firstData = firstString.split(/\r?\n/); + const secondData = + secondString === null || secondString === void 0 + ? void 0 + : secondString.split(/\r?\n/); + + return this.decodeFromLines(firstData, secondData); + } + decodeFromLines(firstData, secondData) { + const storyboard = new Storyboard(); + + this._reset(); + this._setEnabledSections(); + this._lines = [ + ...this._getLines(firstData), + ...(secondData ? this._getLines(secondData) : []), + ]; + + for (let i = 0; i < this._lines.length; ++i) { + const type = this._parseLine(this._lines[i], storyboard); + + if (type === LineType.Break) { + break; + } + } + + storyboard.variables = this._variables; + + return storyboard; + } + _parseLine(line, storyboard) { + if (line.includes("osu file format v")) { + storyboard.fileFormat = Parsing.parseInt(line.split("v")[1]); + + return LineType.FileFormat; + } + + return super._parseLine(line, storyboard); + } + _parseSectionData(line, storyboard) { + switch (this._sectionMap.currentSection) { + case Section.General: + return StoryboardGeneralDecoder.handleLine(line, storyboard); + case Section.Events: + return StoryboardEventDecoder.handleLine(line, storyboard); + case Section.Variables: + return StoryboardVariableDecoder.handleLine(line, this._variables); + } + + super._parseSectionData(line, storyboard); + } + _setEnabledSections() { + super._setEnabledSections(); + this._sectionMap.set(Section.General); + this._sectionMap.set(Section.Variables); + this._sectionMap.set(Section.Events); + } + _preprocessLine(line) { + line = StoryboardVariableDecoder.decodeVariables(line, this._variables); + + return super._preprocessLine(line); + } + _reset() { + super._reset(); + this._sectionMap.reset(); + this._sectionMap.currentSection = Section.Events; + } +} + +class BeatmapDecoder extends SectionDecoder { + constructor() { + super(...arguments); + this._offset = 0; + this._sbLines = null; + } + async decodeFromPath(path, options) { + if (!path.endsWith(FileFormat.Beatmap)) { + throw new Error( + `Wrong file format! Only ${FileFormat.Beatmap} files are supported!` + ); + } + + try { + const data = await this._getFileBuffer(path); + const beatmap = this.decodeFromBuffer(data, options); + + beatmap.fileUpdateDate = await this._getFileUpdateDate(path); + + return beatmap; + } catch (err) { + const reason = err.message || err; + throw new Error(`Failed to decode a beatmap: ${reason}`); + } + } + decodeFromBuffer(data, options) { + return this.decodeFromString(stringifyBuffer(data), options); + } + decodeFromString(str, options) { + str = typeof str !== "string" ? String(str) : str; + + return this.decodeFromLines(str.split(/\r?\n/), options); + } + decodeFromLines(data, options) { + const beatmap = new Beatmap(); + + this._reset(); + this._lines = this._getLines(data); + this._setEnabledSections(typeof options !== "boolean" ? options : {}); + this._sbLines = this._shouldParseStoryboard(options) ? [] : null; + + const fileFormatLine = this._lines[0].trim(); + + if (!fileFormatLine.startsWith("osu file format v")) { + throw new Error("Not a valid beatmap!"); + } + + for (let i = 0; i < this._lines.length; ++i) { + const type = this._parseLine(this._lines[i], beatmap); + + if (type === LineType.Break) { + break; + } + } + + BeatmapTimingPointDecoder.flushPendingPoints(); + + for (let i = 0; i < beatmap.hitObjects.length; ++i) { + beatmap.hitObjects[i].applyDefaults( + beatmap.controlPoints, + beatmap.difficulty + ); + } + + beatmap.hitObjects.sort((a, b) => a.startTime - b.startTime); + + if (this._sbLines && this._sbLines.length) { + const storyboardDecoder = new StoryboardDecoder(); + + beatmap.events.storyboard = storyboardDecoder.decodeFromLines( + this._sbLines + ); + beatmap.events.storyboard.useSkinSprites = beatmap.general.useSkinSprites; + beatmap.events.storyboard.colors = beatmap.colors; + beatmap.events.storyboard.fileFormat = beatmap.fileFormat; + } + + return beatmap; + } + _parseLine(line, beatmap) { + if (line.includes("osu file format v")) { + beatmap.fileFormat = Parsing.parseInt(line.split("v")[1]); + + return LineType.FileFormat; + } + + return super._parseLine(line, beatmap); + } + _parseSectionData(line, beatmap) { + switch (this._sectionMap.currentSection) { + case Section.General: + return BeatmapGeneralDecoder.handleLine(line, beatmap, this._offset); + case Section.Editor: + return BeatmapEditorDecoder.handleLine(line, beatmap); + case Section.Metadata: + return BeatmapMetadataDecoder.handleLine(line, beatmap); + case Section.Difficulty: + return BeatmapDifficultyDecoder.handleLine(line, beatmap); + case Section.Events: + return BeatmapEventDecoder.handleLine( + line, + beatmap, + this._sbLines, + this._offset + ); + case Section.TimingPoints: + return BeatmapTimingPointDecoder.handleLine( + line, + beatmap, + this._offset + ); + case Section.HitObjects: + return BeatmapHitObjectDecoder.handleLine(line, beatmap, this._offset); + } + + super._parseSectionData(line, beatmap); + } + _setEnabledSections(options) { + super._setEnabledSections(options); + this._sectionMap.set( + Section.General, + options === null || options === void 0 ? void 0 : options.parseGeneral + ); + this._sectionMap.set( + Section.Editor, + options === null || options === void 0 ? void 0 : options.parseEditor + ); + this._sectionMap.set( + Section.Metadata, + options === null || options === void 0 ? void 0 : options.parseMetadata + ); + this._sectionMap.set( + Section.Difficulty, + options === null || options === void 0 ? void 0 : options.parseDifficulty + ); + this._sectionMap.set( + Section.Events, + options === null || options === void 0 ? void 0 : options.parseEvents + ); + this._sectionMap.set( + Section.TimingPoints, + options === null || options === void 0 + ? void 0 + : options.parseTimingPoints + ); + this._sectionMap.set( + Section.HitObjects, + options === null || options === void 0 ? void 0 : options.parseHitObjects + ); + } + _shouldParseStoryboard(options) { + let _a, _b; + const parsingOptions = options; + const storyboardFlag = + (_a = + parsingOptions === null || parsingOptions === void 0 + ? void 0 + : parsingOptions.parseStoryboard) !== null && _a !== void 0 + ? _a + : options; + const parseSb = typeof storyboardFlag === "boolean" ? storyboardFlag : true; + const parseEvents = + (_b = + parsingOptions === null || parsingOptions === void 0 + ? void 0 + : parsingOptions.parseEvents) !== null && _b !== void 0 + ? _b + : true; + + return parseEvents && parseSb; + } +} +BeatmapDecoder.EARLY_VERSION_TIMING_OFFSET = 24; + +class ScoreDecoder extends Decoder { + async decodeFromPath(path, parseReplay = true) { + if (!path.endsWith(FileFormat.Replay)) { + throw new Error( + `Wrong file format! Only ${FileFormat.Replay} files are supported!` + ); + } + + try { + const data = await this._getFileBuffer(path); + + return await this.decodeFromBuffer(data, parseReplay); + } catch (err) { + const reason = err.message || err; + throw new Error(`Failed to decode a score: '${reason}'`); + } + } + async decodeFromBuffer(buffer, parseReplay = true) { + const scoreInfo = new ScoreInfo(); + + scoreInfo.id = 2398933774; + scoreInfo.accuracy = 0; + scoreInfo.count50 = 0; + scoreInfo.count100 = 0; + scoreInfo.count300 = 0; + scoreInfo.countGeki = 0; + scoreInfo.countKatu = 0; + scoreInfo.countMiss = 0; + scoreInfo.totalScore = 0; + scoreInfo.maxCombo = 0; + scoreInfo.perfect = false; + scoreInfo.rawMods = 0; + scoreInfo.date = new Date(); + scoreInfo.beatmapHashMD5 = "d41d8cd98f00b204e9800998ecf8427e"; + scoreInfo.username = "Unknown"; + scoreInfo.rulesetId = 0; + + let replay = null; + + replay = new Replay(); + + replay.rawFrames = buffer; + replay.frames = ReplayDecoder.decodeReplayFrames(buffer); + + + return new Score(scoreInfo, replay); + } + _parseScoreId(version, reader) { + if (version >= 20140721) { + return Number(reader.readLong()); + } + + if (version >= 20121008) { + return reader.readInteger(); + } + + return 0; + } +} + +export { + BeatmapDecoder, + BeatmapEncoder, + HittableObject, + HoldableObject, + ScoreDecoder, + ScoreEncoder, + SlidableObject, + SpinnableObject, + StoryboardDecoder, + StoryboardEncoder, +}; diff --git a/nise-replay-viewer/osu-parsers/lib/index.d.ts b/nise-replay-viewer/osu-parsers/lib/index.d.ts new file mode 100644 index 0000000..5b7c004 --- /dev/null +++ b/nise-replay-viewer/osu-parsers/lib/index.d.ts @@ -0,0 +1,528 @@ +import { Beatmap, Storyboard, Score, IBeatmap, IScore, HitObject, IHasCombo, IHoldableObject, HitSample, ISlidableObject, SliderPath, ControlPointInfo, BeatmapDifficultySection, ISpinnableObject } from 'osu-classes'; + +declare enum LineType { + FileFormat = 0, + Section = 1, + Empty = 2, + Data = 3, + Break = 4 +} + +declare enum Section { + General = 'General', + Editor = 'Editor', + Metadata = 'Metadata', + Difficulty = 'Difficulty', + Events = 'Events', + TimingPoints = 'TimingPoints', + Colours = 'Colours', + HitObjects = 'HitObjects', + Variables = 'Variables', + Fonts = 'Fonts', + CatchTheBeat = 'CatchTheBeat', + Mania = 'Mania' +} + +interface IParsingOptions { + /** + * Whether to parse colour section or not. + * This section is only required for beatmap & storyboard rendering stuff + * and doesn't affect beatmap parsing and difficulty & performance calculation at all. + */ + parseColours?: boolean; +} +interface IBeatmapParsingOptions extends IParsingOptions { + /** + * Whether to parse general section or not. + * This section contains very important data like beatmap mode or file format + * and should not be omitted unless you really need to. Different beatmap file formats + * can significantly affect beatmap parsing and difficulty & performance calculations. + */ + parseGeneral?: boolean; + /** + * Whether to parse editor section or not. + * This section isn't required anywhere so it can be disabled safely. + */ + parseEditor?: boolean; + /** + * Whether to parse metadata section or not. + * This section isn't required anywhere so it can be disabled safely. + */ + parseMetadata?: boolean; + /** + * Whether to parse difficulty section or not. + * This section is required for hit object processing and difficulty & performance calculations. + */ + parseDifficulty?: boolean; + /** + * Whether to parse events section or not. + * Events section contains information about breaks, background and storyboard. + * Changing this will also affects storyboard parsing. + */ + parseEvents?: boolean; + /** + * Whether to parse timing point section or not. + * Timing points are required for internal hit object processing. + */ + parseTimingPoints?: boolean; + /** + * Whether to parse hit object section or not. + * If you don't need hit objects you can safely disable this section. + */ + parseHitObjects?: boolean; + /** + * Whether to parse storyboard or not. + * If you don't need storyboard you can safely disable this section. + */ + parseStoryboard?: boolean; +} + +/** + * A basic decoder for readable file formats. + */ +declare abstract class Decoder { + /** + * Tries to read a file by its path in file system. + * @param path A path to the file. + * @throws If file doesn't exist or it can't be read. + * @returns A file buffer. + */ + protected _getFileBuffer(path: string): Promise; + /** + * Tries to get last update date of a file by its path in file system. + * @param path A path to the file. + * @throws If file can't be read. + * @returns Last file update date. + */ + protected _getFileUpdateDate(path: string): Promise; +} + +declare class SectionMap extends Map { + /** + * Current section of this map. + */ + currentSection: Section | null; + /** + * Gets the current state of the specified section. + * @param section Section name. + * @returns Current state of the section. + */ + get(section: Section): boolean; + /** + * Sets the state of the specified section. + * @param section Section name. + * @param state State of the section. + * @returns Reference to this section map. + */ + set(section: Section, state?: boolean): this; + /** + * Resets all section states to enabled and removes current section. + * @returns Reference to this section map. + */ + reset(): this; + get hasEnabledSections(): boolean; + /** + * Check if current section is enabled and should be parsed. + * Unknown sections are disabled by default. + * @returns If this section is enabled. + */ + get isSectionEnabled(): boolean; +} + +/** + * A decoder for human-readable file formats that consist of sections. + */ +declare abstract class SectionDecoder extends Decoder { + /** + * Current data lines. + */ + protected _lines: string[] | null; + /** + * Section map of this decoder. + */ + protected _sectionMap: SectionMap; + protected _getLines(data: any[]): string[]; + protected _parseLine(line: string, output: T): LineType; + protected _parseSectionData(line: string, output: T): void; + protected _preprocessLine(line: string): string; + protected _shouldSkipLine(line: string): boolean; + protected _stripComments(line: string): string; + protected _reset(): void; + /** + * Sets current enabled sections. + * All known sections are enabled by default. + * @param options Parsing options. + */ + protected _setEnabledSections(options?: IParsingOptions): void; +} + +declare type BufferLike = ArrayBufferLike | Uint8Array; + +/** + * A beatmap decoder. + */ +declare class BeatmapDecoder extends SectionDecoder { + /** + * An offset which needs to be applied to old beatmaps (v4 and lower) + * to correct timing changes that were applied at a game client level. + */ + static readonly EARLY_VERSION_TIMING_OFFSET = 24; + /** + * Current offset for all time values. + */ + protected _offset: number; + /** + * Current storyboard lines. + */ + protected _sbLines: string[] | null; + /** + * Performs beatmap decoding from the specified .osu file. + * @param path A path to the .osu file. + * @param options Beatmap parsing options. + * Setting this to boolean will only affect storyboard parsing. + * All sections that weren't specified will be enabled by default. + * @throws If file doesn't exist or can't be decoded. + * @returns A decoded beatmap. + */ + decodeFromPath(path: string, options?: boolean | IBeatmapParsingOptions): Promise; + /** + * Performs beatmap decoding from a data buffer. + * @param data The buffer with beatmap data. + * @param options Beatmap parsing options. + * Setting this to boolean will only affect storyboard parsing. + * All sections that weren't specified will be enabled by default. + * @throws If beatmap data can't be decoded. + * @returns A decoded beatmap. + */ + decodeFromBuffer(data: BufferLike, options?: boolean | IBeatmapParsingOptions): Beatmap; + /** + * Performs beatmap decoding from a string. + * @param str The string with beatmap data. + * @param options Beatmap parsing options. + * Setting this to boolean will only affect storyboard parsing. + * All sections that weren't specified will be enabled by default. + * @throws If beatmap data can't be decoded. + * @returns A decoded beatmap. + */ + decodeFromString(str: string, options?: boolean | IBeatmapParsingOptions): Beatmap; + /** + * Performs beatmap decoding from a string array. + * @param data The array of split lines. + * @param options Beatmap parsing options. + * Setting this to boolean will only affect storyboard parsing. + * @throws If beatmap data can't be decoded. + * @returns A decoded beatmap. + */ + decodeFromLines(data: string[], options?: boolean | IBeatmapParsingOptions): Beatmap; + protected _parseLine(line: string, beatmap: Beatmap): LineType; + protected _parseSectionData(line: string, beatmap: Beatmap): void; + /** + * Sets current enabled sections. + * All known sections are enabled by default. + * @param options Parsing options. + */ + protected _setEnabledSections(options?: IBeatmapParsingOptions): void; + protected _shouldParseStoryboard(options?: boolean | IBeatmapParsingOptions): boolean; +} + +/** + * A storyboard decoder. + */ +declare class StoryboardDecoder extends SectionDecoder { + /** + * Current section name. + */ + private _variables; + /** + * Performs storyboard decoding from the specified `.osu` or `.osb` file. + * If two paths were specified, storyboard decoder will try to combine storyboards. + * + * NOTE: Commands from the `.osb` file take precedence over those + * from the `.osu` file within the layers, as if the commands + * from the `.osb` were appended to the end of the `.osu` commands. + * @param firstPath The path to the main storyboard (`.osu` or `.osb` file). + * @param secondPath The path to the secondary storyboard (`.osb` file). + * @throws If file doesn't exist or can't be decoded. + * @returns A decoded storyboard. + */ + decodeFromPath(firstPath: string, secondPath?: string): Promise; + /** + * Performs storyboard decoding from a data buffer. + * If two data buffers were specified, storyboard decoder will try to combine storyboards. + * + * NOTE: Commands from the `.osb` file take precedence over those + * from the `.osu` file within the layers, as if the commands + * from the `.osb` were appended to the end of the `.osu` commands. + * @param firstBuffer The buffer with the main storyboard data (from `.osu` or `.osb` file). + * @param secondBuffer The buffer with the secondary storyboard data (from `.osb` file). + * @throws If storyboard data can't be decoded. + * @returns A decoded storyboard. + */ + decodeFromBuffer(firstBuffer: BufferLike, secondBuffer?: BufferLike): Storyboard; + /** + * Performs storyboard decoding from a string. + * If two strings were specified, storyboard decoder will try to combine storyboards. + * + * NOTE: Commands from the `.osb` file take precedence over those + * from the `.osu` file within the layers, as if the commands + * from the `.osb` were appended to the end of the `.osu` commands. + * @param firstString The string with the main storyboard data (from `.osu` or `.osb` file). + * @param secondString The string with the secondary storyboard data (from `.osb` file). + * @throws If storyboard data can't be decoded. + * @returns A decoded storyboard. + */ + decodeFromString(firstString: string, secondString?: string): Storyboard; + /** + * Performs storyboard decoding from a string array. + * If two string arrays were specified, storyboard decoder will try to combine storyboards. + * + * NOTE: Commands from the `.osb` file take precedence over those + * from the `.osu` file within the layers, as if the commands + * from the `.osb` were appended to the end of the `.osu` commands. + * @param firstData The string array with the main storyboard data (from `.osu` or `.osb` file). + * @param secondData The string array with the secondary storyboard data (from `.osb` file). + * @throws If storyboard data can't be decoded. + * @returns A decoded storyboard. + */ + decodeFromLines(firstData: string[], secondData?: string[]): Storyboard; + protected _parseLine(line: string, storyboard: Storyboard): LineType; + protected _parseSectionData(line: string, storyboard: Storyboard): void; + /** + * Sets current enabled sections. + * All known sections are enabled by default. + */ + protected _setEnabledSections(): void; + protected _preprocessLine(line: string): string; + protected _reset(): void; +} + +/** + * A score decoder. + */ +declare class ScoreDecoder extends Decoder { + /** + * Performs score decoding from the specified .osr file. + * @param path A path to the .osr file. + * @param parseReplay Should replay be parsed? + * @throws If file doesn't exist or can't be decoded. + * @returns A decoded score. + */ + decodeFromPath(path: string, parseReplay?: boolean): Promise; + /** + * Performs score decoding from a buffer. + * @param buffer The buffer with score data. + * @param parseReplay Should replay be parsed? + * @returns A decoded score. + */ + decodeFromBuffer(buffer: BufferLike, parseReplay?: boolean): Promise; + private _parseScoreId; +} + +/** + * A beatmap encoder. + */ +declare class BeatmapEncoder { + /** + * First playable lazer version. + */ + static readonly FIRST_LAZER_VERSION = 128; + /** + * Performs beatmap encoding to the specified path. + * @param path The path for writing the .osu file. + * @param beatmap The beatmap for encoding. + * @throws If beatmap can't be encoded or file can't be written. + */ + encodeToPath(path: string, beatmap?: IBeatmap): Promise; + /** + * Performs beatmap encoding to a string. + * @param beatmap The beatmap for encoding. + * @returns The string with encoded beatmap data. + */ + encodeToString(beatmap?: IBeatmap): string; +} + +/** + * A storyboard encoder. + */ +declare class StoryboardEncoder { + /** + * Performs storyboard encoding to the specified path. + * @param path The path for writing the .osb file. + * @param storyboard The storyboard for encoding. + * @throws If storyboard can't be encoded or file can't be written. + */ + encodeToPath(path: string, storyboard?: Storyboard): Promise; + /** + * Performs storyboard encoding to a string. + * @param storyboard The storyboard for encoding. + * @returns The string with encoded storyboard data. + */ + encodeToString(storyboard?: Storyboard): string; +} + +/** + * A score encoder. + */ +declare class ScoreEncoder { + /** + * Default game version used if replay is not available. + * It's just the last available osu!lazer version at the moment. + */ + static DEFAULT_GAME_VERSION: number; + /** + * Performs score & replay encoding to the specified path. + * @param path The path for writing the .osr file. + * @param score The score for encoding. + * @param beatmap The beatmap of the replay. + * It is required if replay contains non-legacy frames. + * @throws If score can't be encoded + * @throws If beatmap wasn't provided for non-legacy replay. + * @throws If score can't be encoded or file can't be written. + */ + encodeToPath(path: string, score?: IScore, beatmap?: IBeatmap): Promise; + /** + * Performs score encoding to a buffer. + * @param score The score for encoding. + * @param beatmap The beatmap of the replay. + * It is required if replay contains non-legacy frames. + * @throws If beatmap wasn't provided for non-legacy replay. + * @returns The buffer with encoded score & replay data. + */ + encodeToBuffer(score?: IScore, beatmap?: IBeatmap): Promise; +} + +/** + * A hittable object. + */ +declare class HittableObject extends HitObject implements IHasCombo { + isNewCombo: boolean; + comboOffset: number; + /** + * Creates a copy of this parsed hit. + * Non-primitive properties will be copied via their own clone() method. + * @returns A copied parsed slider. + */ + clone(): this; +} + +/** + * A holdable object. + */ +declare class HoldableObject extends HitObject implements IHoldableObject { + /** + * The time at which the holdable object ends. + */ + endTime: number; + /** + * The samples to be played when each node of the holdable object is hit. + * 0: The first node. + * 1: The first repeat. + * 2: The second repeat. + * ... + * n-1: The last repeat. + * n: The last node. + */ + nodeSamples: HitSample[][]; + /** + * The duration of the holdable object. + */ + get duration(): number; + /** + * Creates a copy of this holdable object. + * Non-primitive properties will be copied via their own clone() method. + * @returns A copied holdable object. + */ + clone(): this; +} + +/** + * A parsed slidable object. + */ +declare class SlidableObject extends HitObject implements ISlidableObject, IHasCombo { + /** + * Scoring distance with a speed-adjusted beat length of 1 second + * (ie. the speed slider balls move through their track). + */ + static BASE_SCORING_DISTANCE: number; + /** + * The duration of this slidable object. + */ + get duration(): number; + /** + * The time at which the slidable object ends. + */ + get endTime(): number; + /** + * The amount of times the length of this slidable object spans. + */ + get spans(): number; + set spans(value: number); + /** + * The duration of a single span of this slidable object. + */ + get spanDuration(): number; + /** + * The positional length of a slidable object. + */ + get distance(): number; + set distance(value: number); + /** + * The amount of times a slidable object repeats. + */ + repeats: number; + /** + * Velocity of this slidable object. + */ + velocity: number; + /** + * The curve of a slidable object. + */ + path: SliderPath; + /** + * The last tick offset of slidable objects in osu!stable. + */ + legacyLastTickOffset: number; + /** + * The samples to be played when each node of the slidable object is hit. + * 0: The first node. + * 1: The first repeat. + * 2: The second repeat. + * ... + * n-1: The last repeat. + * n: The last node. + */ + nodeSamples: HitSample[][]; + isNewCombo: boolean; + comboOffset: number; + applyDefaultsToSelf(controlPoints: ControlPointInfo, difficulty: BeatmapDifficultySection): void; + /** + * Creates a copy of this parsed slider. + * Non-primitive properties will be copied via their own clone() method. + * @returns A copied parsed slider. + */ + clone(): this; +} + +/** + * A parsed spinnable object. + */ +declare class SpinnableObject extends HitObject implements ISpinnableObject, IHasCombo { + /** + * The time at which the spinnable object ends. + */ + endTime: number; + isNewCombo: boolean; + comboOffset: number; + /** + * The duration of this spinnable object. + */ + get duration(): number; + /** + * Creates a copy of this parsed spinner. + * Non-primitive properties will be copied via their own clone() method. + * @returns A copied parsed spinner. + */ + clone(): this; +} + +export { BeatmapDecoder, BeatmapEncoder, HittableObject, HoldableObject, ScoreDecoder, ScoreEncoder, SlidableObject, SpinnableObject, StoryboardDecoder, StoryboardEncoder }; diff --git a/nise-replay-viewer/osu-parsers/package.json b/nise-replay-viewer/osu-parsers/package.json new file mode 100644 index 0000000..ea2c7d7 --- /dev/null +++ b/nise-replay-viewer/osu-parsers/package.json @@ -0,0 +1,65 @@ +{ + "name": "osu-parsers", + "version": "4.1.3", + "description": "A bundle of parsers for osu! file formats based on the osu!lazer source code.", + "exports": { + "node": { + "import": "./lib/node.mjs", + "require": "./lib/node.cjs" + }, + "import": "./lib/browser.mjs" + }, + "types": "./lib/index.d.ts", + "scripts": { + "build": "rollup -c && npm run format", + "test": "jest --verbose", + "fix": "eslint --fix ./src", + "format": "eslint --fix ./lib/** --no-ignore", + "prepublishOnly": "npm run build", + "docs": "npx typedoc" + }, + "keywords": [ + "osu", + "beatmap", + "storyboard", + "score", + "replay", + "parser", + "osu!std", + "osu!taiko", + "osu!mania", + "osu!catch", + ".osu", + ".osb", + ".osr" + ], + "author": "Kionell", + "repository": { + "type": "git", + "url": "https://github.com/kionell/osu-parsers" + }, + "license": "MIT", + "devDependencies": { + "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-typescript": "^8.2.1", + "@types/jest": "^26.0.22", + "@types/node": "^14.18.12", + "@typescript-eslint/eslint-plugin": "^4.20.0", + "@typescript-eslint/parser": "^4.21.0", + "eslint": "^7.23.0", + "eslint-plugin-import": "^2.22.1", + "jest": "^26.6.3", + "rollup": "^2.44.0", + "rollup-plugin-dts": "^3.0.1", + "rollup-plugin-node-externals": "^3.1.2", + "typedoc": "^0.22.10", + "typedoc-plugin-missing-exports": "^1.0.0", + "typescript": "^4.1.5" + }, + "dependencies": { + "lzma-js-simple-v2": "^1.2.2" + }, + "peerDependencies": { + "osu-classes": "^3.0.0" + } +} diff --git a/nise-replay-viewer/package-lock.json b/nise-replay-viewer/package-lock.json new file mode 100644 index 0000000..40bc142 --- /dev/null +++ b/nise-replay-viewer/package-lock.json @@ -0,0 +1,3898 @@ +{ + "name": "sample-p5-editor", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sample-p5-editor", + "version": "0.0.0", + "dependencies": { + "@osujs/core": "^0.0.6", + "@osujs/math": "^0.0.4", + "@radix-ui/react-context-menu": "^2.1.5", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-menubar": "^1.0.4", + "@radix-ui/react-slider": "^1.1.2", + "@radix-ui/react-slot": "^1.0.2", + "@types/react": "^18.2.37", + "@types/react-dom": "^18.2.15", + "@vitejs/plugin-react": "^4.2.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0", + "eventemitter3": "^5.0.1", + "events": "^3.3.0", + "lucide-react": "^0.292.0", + "next-themes": "^0.2.1", + "osu-classes": "^3.0.1", + "osu-parsers": "^4.1.6", + "osu-standard-stable": "^5.0.0", + "p5": "^1.3.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-dropzone": "^14.2.3", + "react-router-dom": "^6.22.2", + "recharts": "^2.10.4", + "sonner": "^1.3.1", + "tailwind-merge": "^2.0.0", + "tailwindcss-animate": "^1.0.7", + "ts-md5": "^1.3.1", + "zustand": "^4.4.1" + }, + "devDependencies": { + "@types/events": "^3.0.3", + "@types/p5": "^0.9.1", + "autoprefixer": "^10.4.16", + "postcss": "^8.4.31", + "tailwindcss": "^3.3.5", + "typescript": "^4.2.3", + "vite": "^4.4.5" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", + "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", + "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.2", + "@babel/parser": "^7.23.3", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.3", + "@babel/types": "^7.23.3", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", + "dependencies": { + "@babel/types": "^7.23.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", + "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "dependencies": { + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.15", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", + "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.2", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz", + "integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.3", + "@babel/types": "^7.23.3", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz", + "integrity": "sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q==", + "dependencies": { + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz", + "integrity": "sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ==", + "dependencies": { + "@floating-ui/core": "^1.5.3", + "@floating-ui/utils": "^0.2.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.6.tgz", + "integrity": "sha512-IB8aCRFxr8nFkdYZgH+Otd9EVQPJoynxeFRGTB8voPoZMRWo8XjYuCRgpI1btvuKY69XMiLnW+ym7zoBHM90Rw==", + "dependencies": { + "@floating-ui/dom": "^1.5.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@next/env": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.0.tgz", + "integrity": "sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==", + "peer": true + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.0.tgz", + "integrity": "sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.0.tgz", + "integrity": "sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.0.tgz", + "integrity": "sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.0.tgz", + "integrity": "sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.0.tgz", + "integrity": "sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.0.tgz", + "integrity": "sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.0.tgz", + "integrity": "sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.0.tgz", + "integrity": "sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.0.tgz", + "integrity": "sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@osujs/core": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@osujs/core/-/core-0.0.6.tgz", + "integrity": "sha512-hnxdcjcMylS95NMtoAYwZZxFMsDkZDKAJk2nK6OCHwPXLaaW4DoVBdBFEoWy1VuuR9yAP8b1yATZtsLeaCH2mA==", + "peerDependencies": { + "@osujs/math": "0.0.4", + "utility-types": "^3.10.0" + } + }, + "node_modules/@osujs/math": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@osujs/math/-/math-0.0.4.tgz", + "integrity": "sha512-4zIvKjsS2ONVQIifRoJLT0BH3YldkOW88AG5yOZ8thjRG9Btdd1l9syAQWSDUchp7t3S9Ducquhctyv2v5lwiA==" + }, + "node_modules/@radix-ui/number": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz", + "integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", + "integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz", + "integrity": "sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collection": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz", + "integrity": "sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz", + "integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz", + "integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-context-menu": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.1.5.tgz", + "integrity": "sha512-R5XaDj06Xul1KGb+WP8qiOh7tKJNz2durpLBXAGZjSVtctcRFCuEvy2gtMwRJGePwQQE5nV77gs4FwRi8T+r2g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-menu": "2.0.6", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dialog": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz", + "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-direction": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz", + "integrity": "sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz", + "integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-escape-keydown": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz", + "integrity": "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz", + "integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-id": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz", + "integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-label": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz", + "integrity": "sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.6.tgz", + "integrity": "sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.5", + "@radix-ui/react-focus-guards": "1.0.1", + "@radix-ui/react-focus-scope": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-popper": "1.1.3", + "@radix-ui/react-portal": "1.0.4", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-roving-focus": "1.0.4", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-callback-ref": "1.0.1", + "aria-hidden": "^1.1.1", + "react-remove-scroll": "2.5.5" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menubar": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.0.4.tgz", + "integrity": "sha512-bHgUo9gayKZfaQcWSSLr++LyS0rgh+MvD89DE4fJ6TkGHvjHgPaBZf44hdka7ogOxIOdj9163J+5xL2Dn4qzzg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-menu": "2.0.6", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-roving-focus": "1.0.4", + "@radix-ui/react-use-controllable-state": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-popper": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz", + "integrity": "sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1", + "@radix-ui/react-use-rect": "1.0.1", + "@radix-ui/react-use-size": "1.0.1", + "@radix-ui/rect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-portal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz", + "integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-primitive": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-presence": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz", + "integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-primitive": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz", + "integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-slot": "1.0.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz", + "integrity": "sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-controllable-state": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slider": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.2.tgz", + "integrity": "sha512-NKs15MJylfzVsCagVSWKhGGLNR1W9qWs+HtgbmjjVUB3B9+lb3PYoXxVju3kOrpf0VKyVCtZp+iTwVoqpa1Chw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/number": "1.0.1", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1", + "@radix-ui/react-use-previous": "1.0.1", + "@radix-ui/react-use-size": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-slot": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", + "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-compose-refs": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", + "integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz", + "integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz", + "integrity": "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-callback-ref": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz", + "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-previous": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz", + "integrity": "sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==", + "dependencies": { + "@babel/runtime": "^7.13.10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz", + "integrity": "sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/rect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz", + "integrity": "sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz", + "integrity": "sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, + "node_modules/@remix-run/router": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz", + "integrity": "sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz", + "integrity": "sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", + "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.2.tgz", + "integrity": "sha512-WAIEVlOCdd/NKRYTsqCpOMHQHemKBEINf8YXMYOtXH0GA7SY0dqMB78P3Uhgfy+4X+/Mlw2wDtlETkN6kQUCMA==" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz", + "integrity": "sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz", + "integrity": "sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz", + "integrity": "sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw==" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==" + }, + "node_modules/@types/events": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz", + "integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", + "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/p5": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@types/p5/-/p5-0.9.1.tgz", + "integrity": "sha512-4glOKdqdBiRWDFZwi/MjHudPV2U4t2L4fTTSacGapfFxyNXzZcAshAjqmrJkCIZcFlhRBEAL7AM95xRDMfrIwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.10", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.10.tgz", + "integrity": "sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==" + }, + "node_modules/@types/react": { + "version": "18.2.37", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.37.tgz", + "integrity": "sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.15", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.15.tgz", + "integrity": "sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg==", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.6.tgz", + "integrity": "sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA==" + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz", + "integrity": "sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==", + "dependencies": { + "@babel/core": "^7.23.3", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.4", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/aria-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz", + "integrity": "sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "engines": { + "node": ">=4" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", + "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001541", + "electron-to-chromium": "^1.4.535", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "peer": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001579", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", + "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/class-variance-authority": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", + "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "dependencies": { + "clsx": "2.0.0" + }, + "funding": { + "url": "https://joebell.co.uk" + } + }, + "node_modules/class-variance-authority/node_modules/clsx": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", + "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "peer": true + }, + "node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==" + }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.588", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.588.tgz", + "integrity": "sha512-soytjxwbgcCu7nh5Pf4S2/4wa6UIu+A3p03U2yVr53qGxi1/VTR3ENI+p50v+UxqqZAfl48j3z55ud7VHIOr9w==" + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-equals": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz", + "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "peer": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "0.292.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.292.0.tgz", + "integrity": "sha512-rRgUkpEHWpa5VCT66YscInCQmQuPCB1RFRzkkxMxg4b+jaL0V12E3riWWR2Sh5OIiUhCwGW/ZExuEO4Az32E6Q==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lzma-js-simple-v2": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/lzma-js-simple-v2/-/lzma-js-simple-v2-1.2.2.tgz", + "integrity": "sha512-dHjXHlgcS8r2K+4t8kAycGE4xMVQxPzMTCrrYhaFEtQDmjXh/A7xq4D88oOfEtjTR9XFzTAML9AuBrm4jXLigA==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/next/-/next-14.1.0.tgz", + "integrity": "sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==", + "peer": true, + "dependencies": { + "@next/env": "14.1.0", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.1.0", + "@next/swc-darwin-x64": "14.1.0", + "@next/swc-linux-arm64-gnu": "14.1.0", + "@next/swc-linux-arm64-musl": "14.1.0", + "@next/swc-linux-x64-gnu": "14.1.0", + "@next/swc-linux-x64-musl": "14.1.0", + "@next/swc-win32-arm64-msvc": "14.1.0", + "@next/swc-win32-ia32-msvc": "14.1.0", + "@next/swc-win32-x64-msvc": "14.1.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-themes": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz", + "integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==", + "peerDependencies": { + "next": "*", + "react": "*", + "react-dom": "*" + } + }, + "node_modules/node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/osu-classes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/osu-classes/-/osu-classes-3.0.1.tgz", + "integrity": "sha512-EI0pMoyUAgrvGHeOywaglHaGpjxhCHtwxPsK7kKJMDGmSgT8lvD3Ebs7vkSNPcKAuBX0VMbfsnSrwE9ArkOXyw==" + }, + "node_modules/osu-parsers": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/osu-parsers/-/osu-parsers-4.1.6.tgz", + "integrity": "sha512-k0PQaWBEZEMiweminI/A4j0lLTvsbHvhU/McMI94yJy+ME1ZfggAOp3vVee1P0Ze0Nu+pT/Ir7b0AlrhJO9IsQ==", + "dependencies": { + "lzma-js-simple-v2": "^1.2.2" + }, + "peerDependencies": { + "osu-classes": "^3.0.1" + } + }, + "node_modules/osu-standard-stable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/osu-standard-stable/-/osu-standard-stable-5.0.0.tgz", + "integrity": "sha512-qCzS1DFStHjgeDZguLRY5k4OgJSNXHG+sUdi1jm2Xwgk23QsyexwRQyTs5phFMuAnQmxeyjzWELLHOo99A/gMA==", + "peerDependencies": { + "osu-classes": "^3.0.0" + } + }, + "node_modules/p5": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/p5/-/p5-1.3.1.tgz", + "integrity": "sha512-g7W2htgEwiAEGcl0WHccAJKbunUJwrUojUSR9+KihphJ33p5VpDdh1K8pDx4ppYjOr/lVEXaZ1XXDj27nwlNOg==", + "license": "LGPL-2.1" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", + "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" + }, + "engines": { + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-dropzone": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz", + "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.6.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-remove-scroll": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz", + "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==", + "dependencies": { + "react-remove-scroll-bar": "^2.3.3", + "react-style-singleton": "^2.2.1", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.0", + "use-sidecar": "^1.1.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz", + "integrity": "sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==", + "dependencies": { + "react-style-singleton": "^2.2.1", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-router": { + "version": "6.22.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.2.tgz", + "integrity": "sha512-YD3Dzprzpcq+tBMHBS822tCjnWD3iIZbTeSXMY9LPSG541EfoBGyZ3bS25KEnaZjLcmQpw2AVLkFyfgXY8uvcw==", + "dependencies": { + "@remix-run/router": "1.15.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.22.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.2.tgz", + "integrity": "sha512-WgqxD2qySEIBPZ3w0sHH+PUAiamDeszls9tzqMPBDA1YYVucTBXLU7+gtRfcSnhe92A3glPnvSxK2dhNoAVOIQ==", + "dependencies": { + "@remix-run/router": "1.15.2", + "react-router": "6.22.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-smooth": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.5.tgz", + "integrity": "sha512-BMP2Ad42tD60h0JW6BFaib+RJuV5dsXJK9Baxiv/HlNFjvRLqA9xrNKxVWnUIZPQfzUwGXIlU/dSYLU+54YGQA==", + "dependencies": { + "fast-equals": "^5.0.0", + "react-transition-group": "2.9.0" + }, + "peerDependencies": { + "prop-types": "^15.6.0", + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", + "integrity": "sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==", + "dependencies": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "dependencies": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/recharts": { + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.10.4.tgz", + "integrity": "sha512-/Q7/wdf8bW91lN3NEeCjL9RWfaiXQViJFgdnas4Eix/I8B9HAI3tHHK/CW/zDfgRMh4fzW1zlfjoz1IAapLO1Q==", + "dependencies": { + "clsx": "^2.0.0", + "eventemitter3": "^4.0.1", + "lodash": "^4.17.19", + "react-is": "^16.10.2", + "react-smooth": "^2.0.5", + "recharts-scale": "^0.4.4", + "tiny-invariant": "^1.3.1", + "victory-vendor": "^36.6.8" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "prop-types": "^15.6.0", + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/recharts-scale": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", + "dependencies": { + "decimal.js-light": "^2.4.1" + } + }, + "node_modules/recharts/node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sonner": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.3.1.tgz", + "integrity": "sha512-+rOAO56b2eI3q5BtgljERSn2umRk63KFIvgb2ohbZ5X+Eb5u+a/7/0ZgswYqgBMg8dyl7n6OXd9KasA8QF9ToA==", + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "peer": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "peer": true, + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/sucrase": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", + "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.0.tgz", + "integrity": "sha512-SqqhhaL0T06SW59+JVNfAqKdqLs0497esifRrZ7jOaefP3o64fdFNDMrAQWZFMxTLJPiHVjRLUywT8uFz1xNWQ==", + "dependencies": { + "@babel/runtime": "^7.23.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz", + "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss-animate": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz", + "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==", + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", + "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + }, + "node_modules/ts-md5": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz", + "integrity": "sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/typescript": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "optional": true, + "peer": true + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-callback-ref": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.1.tgz", + "integrity": "sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz", + "integrity": "sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "^16.9.0 || ^17.0.0 || ^18.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utility-types": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz", + "integrity": "sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==", + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/victory-vendor": { + "version": "36.8.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.8.2.tgz", + "integrity": "sha512-NfSQi7ISCdBbDpn3b6rg+8RpFZmWIM9mcks48BbogHE2F6h1XKdA34oiCKP5hP1OGvTotDRzsexiJKzrK4Exuw==", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/zustand": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.1.tgz", + "integrity": "sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/nise-replay-viewer/package.json b/nise-replay-viewer/package.json new file mode 100644 index 0000000..86af9af --- /dev/null +++ b/nise-replay-viewer/package.json @@ -0,0 +1,52 @@ +{ + "name": "sample-p5-editor", + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vite build", + "serve": "vite preview", + "tsc": "tsc" + }, + "devDependencies": { + "@types/events": "^3.0.3", + "@types/p5": "^0.9.1", + "autoprefixer": "^10.4.16", + "postcss": "^8.4.31", + "tailwindcss": "^3.3.5", + "typescript": "^4.2.3", + "vite": "^4.4.5" + }, + "dependencies": { + "@osujs/core": "^0.0.6", + "@osujs/math": "^0.0.4", + "@radix-ui/react-context-menu": "^2.1.5", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-menubar": "^1.0.4", + "@radix-ui/react-slider": "^1.1.2", + "@radix-ui/react-slot": "^1.0.2", + "@types/react": "^18.2.37", + "@types/react-dom": "^18.2.15", + "@vitejs/plugin-react": "^4.2.0", + "class-variance-authority": "^0.7.0", + "clsx": "^2.0.0", + "eventemitter3": "^5.0.1", + "events": "^3.3.0", + "lucide-react": "^0.292.0", + "next-themes": "^0.2.1", + "osu-classes": "^3.0.1", + "osu-parsers": "^4.1.6", + "osu-standard-stable": "^5.0.0", + "p5": "^1.3.1", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-dropzone": "^14.2.3", + "react-router-dom": "^6.22.2", + "recharts": "^2.10.4", + "sonner": "^1.3.1", + "tailwind-merge": "^2.0.0", + "tailwindcss-animate": "^1.0.7", + "ts-md5": "^1.3.1", + "zustand": "^4.4.1" + } +} diff --git a/nise-replay-viewer/postcss.config.js b/nise-replay-viewer/postcss.config.js new file mode 100644 index 0000000..33ad091 --- /dev/null +++ b/nise-replay-viewer/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/nise-replay-viewer/public/ctrl.svg b/nise-replay-viewer/public/ctrl.svg new file mode 100644 index 0000000..f081ae0 --- /dev/null +++ b/nise-replay-viewer/public/ctrl.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/nise-replay-viewer/public/cursor.png b/nise-replay-viewer/public/cursor.png new file mode 100644 index 0000000..de5198e Binary files /dev/null and b/nise-replay-viewer/public/cursor.png differ diff --git a/nise-replay-viewer/public/cursortrail.png b/nise-replay-viewer/public/cursortrail.png new file mode 100644 index 0000000..901e6b6 Binary files /dev/null and b/nise-replay-viewer/public/cursortrail.png differ diff --git a/nise-replay-viewer/public/default0.png b/nise-replay-viewer/public/default0.png new file mode 100644 index 0000000..f0d7289 Binary files /dev/null and b/nise-replay-viewer/public/default0.png differ diff --git a/nise-replay-viewer/public/default1.png b/nise-replay-viewer/public/default1.png new file mode 100644 index 0000000..019ab83 Binary files /dev/null and b/nise-replay-viewer/public/default1.png differ diff --git a/nise-replay-viewer/public/default2.png b/nise-replay-viewer/public/default2.png new file mode 100644 index 0000000..997dc67 Binary files /dev/null and b/nise-replay-viewer/public/default2.png differ diff --git a/nise-replay-viewer/public/default3.png b/nise-replay-viewer/public/default3.png new file mode 100644 index 0000000..4da4f9b Binary files /dev/null and b/nise-replay-viewer/public/default3.png differ diff --git a/nise-replay-viewer/public/default4.png b/nise-replay-viewer/public/default4.png new file mode 100644 index 0000000..061d48a Binary files /dev/null and b/nise-replay-viewer/public/default4.png differ diff --git a/nise-replay-viewer/public/default5.png b/nise-replay-viewer/public/default5.png new file mode 100644 index 0000000..b9b1b87 Binary files /dev/null and b/nise-replay-viewer/public/default5.png differ diff --git a/nise-replay-viewer/public/default6.png b/nise-replay-viewer/public/default6.png new file mode 100644 index 0000000..fa14970 Binary files /dev/null and b/nise-replay-viewer/public/default6.png differ diff --git a/nise-replay-viewer/public/default7.png b/nise-replay-viewer/public/default7.png new file mode 100644 index 0000000..767046b Binary files /dev/null and b/nise-replay-viewer/public/default7.png differ diff --git a/nise-replay-viewer/public/default8.png b/nise-replay-viewer/public/default8.png new file mode 100644 index 0000000..b17fb12 Binary files /dev/null and b/nise-replay-viewer/public/default8.png differ diff --git a/nise-replay-viewer/public/default9.png b/nise-replay-viewer/public/default9.png new file mode 100644 index 0000000..32e7006 Binary files /dev/null and b/nise-replay-viewer/public/default9.png differ diff --git a/nise-replay-viewer/public/ekey.svg b/nise-replay-viewer/public/ekey.svg new file mode 100644 index 0000000..95a09ea --- /dev/null +++ b/nise-replay-viewer/public/ekey.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/nise-replay-viewer/public/fav.png b/nise-replay-viewer/public/fav.png new file mode 100644 index 0000000..43617fb Binary files /dev/null and b/nise-replay-viewer/public/fav.png differ diff --git a/nise-replay-viewer/public/gitlogo.png b/nise-replay-viewer/public/gitlogo.png new file mode 100644 index 0000000..b4a32e3 Binary files /dev/null and b/nise-replay-viewer/public/gitlogo.png differ diff --git a/nise-replay-viewer/public/hitcircle.png b/nise-replay-viewer/public/hitcircle.png new file mode 100644 index 0000000..cf68cf9 Binary files /dev/null and b/nise-replay-viewer/public/hitcircle.png differ diff --git a/nise-replay-viewer/public/hitcircleoverlay.png b/nise-replay-viewer/public/hitcircleoverlay.png new file mode 100644 index 0000000..a79aad2 Binary files /dev/null and b/nise-replay-viewer/public/hitcircleoverlay.png differ diff --git a/nise-replay-viewer/public/icon.png b/nise-replay-viewer/public/icon.png new file mode 100644 index 0000000..43617fb Binary files /dev/null and b/nise-replay-viewer/public/icon.png differ diff --git a/nise-replay-viewer/public/mod_dt.png b/nise-replay-viewer/public/mod_dt.png new file mode 100644 index 0000000..c03400b Binary files /dev/null and b/nise-replay-viewer/public/mod_dt.png differ diff --git a/nise-replay-viewer/public/mod_ez.png b/nise-replay-viewer/public/mod_ez.png new file mode 100644 index 0000000..ed60fbc Binary files /dev/null and b/nise-replay-viewer/public/mod_ez.png differ diff --git a/nise-replay-viewer/public/mod_fl.png b/nise-replay-viewer/public/mod_fl.png new file mode 100644 index 0000000..baf0344 Binary files /dev/null and b/nise-replay-viewer/public/mod_fl.png differ diff --git a/nise-replay-viewer/public/mod_hd.png b/nise-replay-viewer/public/mod_hd.png new file mode 100644 index 0000000..880c8ef Binary files /dev/null and b/nise-replay-viewer/public/mod_hd.png differ diff --git a/nise-replay-viewer/public/mod_hr.png b/nise-replay-viewer/public/mod_hr.png new file mode 100644 index 0000000..71b7129 Binary files /dev/null and b/nise-replay-viewer/public/mod_hr.png differ diff --git a/nise-replay-viewer/public/mod_ht.png b/nise-replay-viewer/public/mod_ht.png new file mode 100644 index 0000000..4a6c039 Binary files /dev/null and b/nise-replay-viewer/public/mod_ht.png differ diff --git a/nise-replay-viewer/public/mod_nc.png b/nise-replay-viewer/public/mod_nc.png new file mode 100644 index 0000000..54cf8ff Binary files /dev/null and b/nise-replay-viewer/public/mod_nc.png differ diff --git a/nise-replay-viewer/public/mod_nf.png b/nise-replay-viewer/public/mod_nf.png new file mode 100644 index 0000000..1fe3902 Binary files /dev/null and b/nise-replay-viewer/public/mod_nf.png differ diff --git a/nise-replay-viewer/public/mod_nm.png b/nise-replay-viewer/public/mod_nm.png new file mode 100644 index 0000000..fa9cb6d Binary files /dev/null and b/nise-replay-viewer/public/mod_nm.png differ diff --git a/nise-replay-viewer/public/mod_pf.png b/nise-replay-viewer/public/mod_pf.png new file mode 100644 index 0000000..1c8b404 Binary files /dev/null and b/nise-replay-viewer/public/mod_pf.png differ diff --git a/nise-replay-viewer/public/mod_sd.png b/nise-replay-viewer/public/mod_sd.png new file mode 100644 index 0000000..b9a6d1e Binary files /dev/null and b/nise-replay-viewer/public/mod_sd.png differ diff --git a/nise-replay-viewer/public/mouse.svg b/nise-replay-viewer/public/mouse.svg new file mode 100644 index 0000000..cacfb58 --- /dev/null +++ b/nise-replay-viewer/public/mouse.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/nise-replay-viewer/public/qkey.svg b/nise-replay-viewer/public/qkey.svg new file mode 100644 index 0000000..ead1eb1 --- /dev/null +++ b/nise-replay-viewer/public/qkey.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/nise-replay-viewer/public/radix.png b/nise-replay-viewer/public/radix.png new file mode 100644 index 0000000..0c9f0dd Binary files /dev/null and b/nise-replay-viewer/public/radix.png differ diff --git a/nise-replay-viewer/public/scroll.svg b/nise-replay-viewer/public/scroll.svg new file mode 100644 index 0000000..5ab8310 --- /dev/null +++ b/nise-replay-viewer/public/scroll.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/nise-replay-viewer/public/sliderb0.png b/nise-replay-viewer/public/sliderb0.png new file mode 100644 index 0000000..0b08aa2 Binary files /dev/null and b/nise-replay-viewer/public/sliderb0.png differ diff --git a/nise-replay-viewer/public/sliderfollowcircle.png b/nise-replay-viewer/public/sliderfollowcircle.png new file mode 100644 index 0000000..f666b62 Binary files /dev/null and b/nise-replay-viewer/public/sliderfollowcircle.png differ diff --git a/nise-replay-viewer/public/space.svg b/nise-replay-viewer/public/space.svg new file mode 100644 index 0000000..146af9c --- /dev/null +++ b/nise-replay-viewer/public/space.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/nise-replay-viewer/public/vite.svg b/nise-replay-viewer/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/nise-replay-viewer/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/nise-replay-viewer/src/decorators/hook.ts b/nise-replay-viewer/src/decorators/hook.ts new file mode 100644 index 0000000..fd99bdc --- /dev/null +++ b/nise-replay-viewer/src/decorators/hook.ts @@ -0,0 +1,11 @@ +import { Events, hook } from "@/hooks"; + +export function Hook(event: Events): any { + return function ( + _target: any, + _propertyKey: string, + descriptor: PropertyDescriptor + ) { + hook({ event, callback: descriptor.value }); + }; +} diff --git a/nise-replay-viewer/src/decorators/singleton.ts b/nise-replay-viewer/src/decorators/singleton.ts new file mode 100644 index 0000000..fa83cd1 --- /dev/null +++ b/nise-replay-viewer/src/decorators/singleton.ts @@ -0,0 +1,14 @@ +export function Singleton any>(ctr: T): T { + let instance: T; + + return class { + constructor(...args: any[]) { + if (instance) { + return instance; + } + + instance = new ctr(...args); + return instance; + } + } as T; +} diff --git a/nise-replay-viewer/src/globals.css b/nise-replay-viewer/src/globals.css new file mode 100644 index 0000000..52a8d2d --- /dev/null +++ b/nise-replay-viewer/src/globals.css @@ -0,0 +1,76 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 0 0% 3.9%; + + --card: 0 0% 100%; + --card-foreground: 0 0% 3.9%; + + --popover: 0 0% 100%; + --popover-foreground: 0 0% 3.9%; + + --primary: 0 0% 9%; + --primary-foreground: 0 0% 98%; + + --secondary: 0 0% 96.1%; + --secondary-foreground: 0 0% 9%; + + --muted: 0 0% 96.1%; + --muted-foreground: 0 0% 45.1%; + + --accent: 0 0% 96.1%; + --accent-foreground: 0 0% 9%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 0 0% 98%; + + --border: 0 0% 89.8%; + --input: 0 0% 89.8%; + --ring: 0 0% 3.9%; + + --radius: 0.5rem; + } + + .dark { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} \ No newline at end of file diff --git a/nise-replay-viewer/src/hooks.ts b/nise-replay-viewer/src/hooks.ts new file mode 100644 index 0000000..f70058b --- /dev/null +++ b/nise-replay-viewer/src/hooks.ts @@ -0,0 +1,38 @@ +export interface Hook { + event: T; + callback: (...args: any) => boolean | void; +} + +export enum Events { + setup, + draw, + preload, + resize, + mousePressed, + mouseDragged, + mouseReleased, + mouseWheel, + keyPressed, + keyReleased, +} + +const hooks: Map[]> = new Map(); + +export function hook({ event, callback }: Hook) { + if (!hooks.get(event)) { + hooks.set(event, []); + } + hooks.set(event, [...hooks.get(event)!, { event, callback }]); +} + +export function hookable(event: Events) { + return (...args: any) => { + const hookList = hooks.get(event); + + if (!hookList?.length) return; + + for (const hook of hookList) { + hook.callback(...args); + } + }; +} diff --git a/nise-replay-viewer/src/hooks/canvasControls.ts b/nise-replay-viewer/src/hooks/canvasControls.ts new file mode 100644 index 0000000..8966401 --- /dev/null +++ b/nise-replay-viewer/src/hooks/canvasControls.ts @@ -0,0 +1,63 @@ +import { Hook } from "@/decorators/hook"; +import { Events } from "@/hooks"; +import { p } from "@/utils"; +import p5 from "p5"; + +export let canvasDragging: boolean; +export let canvasDragStart: p5.Vector; +export let canvasMultiplier: number; +export let canvasTranslation: p5.Vector; + +export class CanvasControlHooks { + @Hook(Events.setup) + static setupCanvasControls() { + canvasDragStart = p.createVector(0, 0); + canvasDragging = false; + canvasMultiplier = p.windowHeight / 384; + canvasTranslation = p.createVector(0, 0); + } + + @Hook(Events.mousePressed) + static mousePressed() { + if (p.mouseButton === p.CENTER) { + canvasDragging = true; + canvasDragStart = p.createVector(p.mouseX, p.mouseY); + } + } + + @Hook(Events.mouseDragged) + static mouseDragged() { + if (canvasDragging) { + const mousePos = p.createVector(p.mouseX, p.mouseY); + const delta = mousePos.copy().sub(canvasDragStart).div(canvasMultiplier); + canvasTranslation.add(delta); + canvasDragStart = mousePos; + } + } + + @Hook(Events.mouseReleased) + static mouseReleased() { + canvasDragging = false; + } + + @Hook(Events.mouseWheel) + static mouseWheel(event: any) { + if (!p.keyIsDown(17)) { + return; + } + const zoom = event.deltaY > 0 ? 100 : -100; + const oldScale = canvasMultiplier; + const multiplierChange = zoom * 0.0008 * oldScale; + canvasMultiplier -= multiplierChange; + + const newScale = canvasMultiplier; + const mousePos = p.createVector(p.mouseX, p.mouseY); + const mousePosScaled = mousePos.copy().div(oldScale); + const mousePosScaledNew = mousePos.copy().div(newScale); + const delta = mousePosScaledNew.copy().sub(mousePosScaled); + canvasTranslation.add(delta); + event.preventDefault(); + + return false; + } +} diff --git a/nise-replay-viewer/src/hooks/osuControls.ts b/nise-replay-viewer/src/hooks/osuControls.ts new file mode 100644 index 0000000..5081975 --- /dev/null +++ b/nise-replay-viewer/src/hooks/osuControls.ts @@ -0,0 +1,46 @@ +import { Hook } from "@/decorators/hook"; +import { Events } from "@/hooks"; +import { OsuRenderer } from "@/osu/OsuRenderer"; +import { p, state } from "@/utils"; + +export class OsuControlHooks { + @Hook(Events.keyPressed) + static keyPressed() { + if (p.keyCode == 32) OsuRenderer.setPlaying(!OsuRenderer.playing); + } + + @Hook(Events.mouseWheel) + static mouseWheel(event: WheelEvent) { + if (event.ctrlKey) return; + const currentState = state.getState(); + + if ( + currentState.achivementsDialog || + currentState.dataAnalysisDialog || + currentState.metadataEditorDialog || + currentState.openDialog || + currentState.saveDialog + ) + return; + + if (event.deltaY > 0) { + OsuRenderer.setTime(OsuRenderer.time + 35); + } else { + OsuRenderer.setTime(OsuRenderer.time - 35); + } + } + + @Hook(Events.mousePressed) + static mousePressed(event: WheelEvent) { + const currentState = state.getState(); + + if ( + currentState.achivementsDialog || + currentState.dataAnalysisDialog || + currentState.metadataEditorDialog || + currentState.openDialog || + currentState.saveDialog + ) + return; + } +} diff --git a/nise-replay-viewer/src/hooks/p5Base.ts b/nise-replay-viewer/src/hooks/p5Base.ts new file mode 100644 index 0000000..a63c866 --- /dev/null +++ b/nise-replay-viewer/src/hooks/p5Base.ts @@ -0,0 +1,47 @@ +import { Events } from "@/hooks"; +import { Renderer } from "@/renderer"; +import { p } from "@/utils"; +import { + canvasDragging, + canvasMultiplier, + canvasTranslation, +} from "./canvasControls"; +import { Hook } from "@/decorators/hook"; + +export class p5Hooks { + @Hook(Events.setup) + static setup() { + p.createCanvas(p.windowWidth, p.windowHeight); + p.imageMode(p.CENTER); + p.frameRate(120); + Renderer.setup(); + Renderer.mouse = p.createVector(); + } + + @Hook(Events.draw) + static draw() { + p.cursor("default"); + if (canvasDragging) { + p.cursor("grabbing"); + } + + p.background(0); + p.scale(canvasMultiplier); + p.translate(canvasTranslation.x, canvasTranslation.y); + + const translated = p.createVector(p.mouseX, p.mouseY); + translated.mult(1 / canvasMultiplier); + translated.sub(canvasTranslation); + Renderer.mouse.set(translated); + + Renderer.draw(); + + p.translate(-canvasTranslation.x, -canvasTranslation.y); + p.scale(1 / canvasMultiplier); + } + + @Hook(Events.resize) + static resize() { + p.resizeCanvas(p.windowWidth, p.windowHeight); + } +} diff --git a/nise-replay-viewer/src/hooks/starter.ts b/nise-replay-viewer/src/hooks/starter.ts new file mode 100644 index 0000000..01ca813 --- /dev/null +++ b/nise-replay-viewer/src/hooks/starter.ts @@ -0,0 +1,4 @@ +import "./canvasControls"; +import "./osuControls"; +import "./p5Base"; +import "./tooling"; diff --git a/nise-replay-viewer/src/hooks/tooling.ts b/nise-replay-viewer/src/hooks/tooling.ts new file mode 100644 index 0000000..77ef46e --- /dev/null +++ b/nise-replay-viewer/src/hooks/tooling.ts @@ -0,0 +1,29 @@ +import { Hook } from "@/decorators/hook"; +import { Events } from "@/hooks"; +import { Tool } from "@/tooling/tool"; + +export class Tooling { + static currentTool: Tool | undefined; + + @Hook(Events.mousePressed) + static mousePressed() { + if (!this.currentTool) return; + this.currentTool.mousePressed(); + } + + @Hook(Events.mousePressed) + static mouseReleased() { + if (!this.currentTool) return; + this.currentTool.mouseReleased(); + } + + @Hook(Events.draw) + static tick() { + if (!this.currentTool) return; + this.currentTool.tick(); + } + + static purge() { + this.currentTool = undefined; + } +} diff --git a/nise-replay-viewer/src/interface/App.tsx b/nise-replay-viewer/src/interface/App.tsx new file mode 100644 index 0000000..449d6d8 --- /dev/null +++ b/nise-replay-viewer/src/interface/App.tsx @@ -0,0 +1,38 @@ +import {AboutDialog} from "./composites/about-dialog"; +import {AnalysisSheet} from "./composites/analysis.-sheet"; +import {Navbar} from "./composites/Menu"; +import {SongSlider} from "./composites/song-slider"; +import {Helper} from "./composites/helper"; +import {useEffect, useState} from "react"; +import {OsuRenderer} from "@/osu/OsuRenderer"; + +export function App() { + + const [replayId, setReplayId] = useState(""); + + useEffect(() => { + let pathReplayId = location.pathname.slice(1, location.pathname.length); + + const loadReplay = async () => { + // TODO: Check for security? + await OsuRenderer.loadReplayFromUrl(`http://localhost:8080/score/${pathReplayId}/replay`); + OsuRenderer.setPlaying(true); + // await OsuRenderer.loadReplayFromUrl(`https://nise.moe/api/score/${pathReplayId}/replay`); + }; + + if(replayId !== pathReplayId) { + setReplayId(pathReplayId); + loadReplay(); + } + }, [location.pathname]); + + return ( + <> + + + + + + + ); +} diff --git a/nise-replay-viewer/src/interface/components/theme-provider.tsx b/nise-replay-viewer/src/interface/components/theme-provider.tsx new file mode 100644 index 0000000..7b9eeb2 --- /dev/null +++ b/nise-replay-viewer/src/interface/components/theme-provider.tsx @@ -0,0 +1,73 @@ +import { createContext, useContext, useEffect, useState } from "react"; + +type Theme = "dark" | "light" | "system"; + +type ThemeProviderProps = { + children: React.ReactNode; + defaultTheme?: Theme; + storageKey?: string; +}; + +type ThemeProviderState = { + theme: Theme; + setTheme: (theme: Theme) => void; +}; + +const initialState: ThemeProviderState = { + theme: "system", + setTheme: () => null, +}; + +const ThemeProviderContext = createContext(initialState); + +export function ThemeProvider({ + children, + defaultTheme = "system", + storageKey = "vite-ui-theme", + ...props +}: ThemeProviderProps) { + const [theme, setTheme] = useState( + () => (localStorage.getItem(storageKey) as Theme) || defaultTheme + ); + + useEffect(() => { + const root = window.document.documentElement; + + root.classList.remove("light", "dark"); + + if (theme === "system") { + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") + .matches + ? "dark" + : "light"; + + root.classList.add(systemTheme); + return; + } + + root.classList.add(theme); + }, [theme]); + + const value = { + theme, + setTheme: (theme: Theme) => { + localStorage.setItem(storageKey, theme); + setTheme(theme); + }, + }; + + return ( + + {children} + + ); +} + +export const useTheme = () => { + const context = useContext(ThemeProviderContext); + + if (context === undefined) + throw new Error("useTheme must be used within a ThemeProvider"); + + return context; +}; diff --git a/nise-replay-viewer/src/interface/components/ui/badge.tsx b/nise-replay-viewer/src/interface/components/ui/badge.tsx new file mode 100644 index 0000000..f000e3e --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ) +} + +export { Badge, badgeVariants } diff --git a/nise-replay-viewer/src/interface/components/ui/button.tsx b/nise-replay-viewer/src/interface/components/ui/button.tsx new file mode 100644 index 0000000..0ba4277 --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/button.tsx @@ -0,0 +1,56 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + } +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/nise-replay-viewer/src/interface/components/ui/card.tsx b/nise-replay-viewer/src/interface/components/ui/card.tsx new file mode 100644 index 0000000..afa13ec --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/card.tsx @@ -0,0 +1,79 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/nise-replay-viewer/src/interface/components/ui/context-menu.tsx b/nise-replay-viewer/src/interface/components/ui/context-menu.tsx new file mode 100644 index 0000000..3e52999 --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/context-menu.tsx @@ -0,0 +1,198 @@ +import * as React from "react" +import * as ContextMenuPrimitive from "@radix-ui/react-context-menu" +import { Check, ChevronRight, Circle } from "lucide-react" + +import { cn } from "@/lib/utils" + +const ContextMenu = ContextMenuPrimitive.Root + +const ContextMenuTrigger = ContextMenuPrimitive.Trigger + +const ContextMenuGroup = ContextMenuPrimitive.Group + +const ContextMenuPortal = ContextMenuPrimitive.Portal + +const ContextMenuSub = ContextMenuPrimitive.Sub + +const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup + +const ContextMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName + +const ContextMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName + +const ContextMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + +)) +ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName + +const ContextMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName + +const ContextMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +ContextMenuCheckboxItem.displayName = + ContextMenuPrimitive.CheckboxItem.displayName + +const ContextMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName + +const ContextMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName + +const ContextMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName + +const ContextMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +ContextMenuShortcut.displayName = "ContextMenuShortcut" + +export { + ContextMenu, + ContextMenuTrigger, + ContextMenuContent, + ContextMenuItem, + ContextMenuCheckboxItem, + ContextMenuRadioItem, + ContextMenuLabel, + ContextMenuSeparator, + ContextMenuShortcut, + ContextMenuGroup, + ContextMenuPortal, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, + ContextMenuRadioGroup, +} diff --git a/nise-replay-viewer/src/interface/components/ui/dialog.tsx b/nise-replay-viewer/src/interface/components/ui/dialog.tsx new file mode 100644 index 0000000..c23630e --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/dialog.tsx @@ -0,0 +1,120 @@ +import * as React from "react" +import * as DialogPrimitive from "@radix-ui/react-dialog" +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = "DialogHeader" + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = "DialogFooter" + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/nise-replay-viewer/src/interface/components/ui/input.tsx b/nise-replay-viewer/src/interface/components/ui/input.tsx new file mode 100644 index 0000000..677d05f --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/input.tsx @@ -0,0 +1,25 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" + +export { Input } diff --git a/nise-replay-viewer/src/interface/components/ui/label.tsx b/nise-replay-viewer/src/interface/components/ui/label.tsx new file mode 100644 index 0000000..683faa7 --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/nise-replay-viewer/src/interface/components/ui/menubar.tsx b/nise-replay-viewer/src/interface/components/ui/menubar.tsx new file mode 100644 index 0000000..d11c299 --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/menubar.tsx @@ -0,0 +1,234 @@ +import * as React from "react" +import * as MenubarPrimitive from "@radix-ui/react-menubar" +import { Check, ChevronRight, Circle } from "lucide-react" + +import { cn } from "@/lib/utils" + +const MenubarMenu = MenubarPrimitive.Menu + +const MenubarGroup = MenubarPrimitive.Group + +const MenubarPortal = MenubarPrimitive.Portal + +const MenubarSub = MenubarPrimitive.Sub + +const MenubarRadioGroup = MenubarPrimitive.RadioGroup + +const Menubar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +Menubar.displayName = MenubarPrimitive.Root.displayName + +const MenubarTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName + +const MenubarSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)) +MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName + +const MenubarSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName + +const MenubarContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>( + ( + { className, align = "start", alignOffset = -4, sideOffset = 8, ...props }, + ref + ) => ( + + + + ) +) +MenubarContent.displayName = MenubarPrimitive.Content.displayName + +const MenubarItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +MenubarItem.displayName = MenubarPrimitive.Item.displayName + +const MenubarCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)) +MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName + +const MenubarRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)) +MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName + +const MenubarLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean + } +>(({ className, inset, ...props }, ref) => ( + +)) +MenubarLabel.displayName = MenubarPrimitive.Label.displayName + +const MenubarSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName + +const MenubarShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ) +} +MenubarShortcut.displayname = "MenubarShortcut" + +export { + Menubar, + MenubarMenu, + MenubarTrigger, + MenubarContent, + MenubarItem, + MenubarSeparator, + MenubarLabel, + MenubarCheckboxItem, + MenubarRadioGroup, + MenubarRadioItem, + MenubarPortal, + MenubarSubContent, + MenubarSubTrigger, + MenubarGroup, + MenubarSub, + MenubarShortcut, +} diff --git a/nise-replay-viewer/src/interface/components/ui/sheet.tsx b/nise-replay-viewer/src/interface/components/ui/sheet.tsx new file mode 100644 index 0000000..d64a6fa --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/sheet.tsx @@ -0,0 +1,138 @@ +import * as React from "react" +import * as SheetPrimitive from "@radix-ui/react-dialog" +import { cva, type VariantProps } from "class-variance-authority" +import { X } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Sheet = SheetPrimitive.Root + +const SheetTrigger = SheetPrimitive.Trigger + +const SheetClose = SheetPrimitive.Close + +const SheetPortal = SheetPrimitive.Portal + +const SheetOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetOverlay.displayName = SheetPrimitive.Overlay.displayName + +const sheetVariants = cva( + "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500", + { + variants: { + side: { + top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top", + bottom: + "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom", + left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm", + right: + "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm", + }, + }, + defaultVariants: { + side: "right", + }, + } +) + +interface SheetContentProps + extends React.ComponentPropsWithoutRef, + VariantProps {} + +const SheetContent = React.forwardRef< + React.ElementRef, + SheetContentProps +>(({ side = "right", className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +SheetContent.displayName = SheetPrimitive.Content.displayName + +const SheetHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +SheetHeader.displayName = "SheetHeader" + +const SheetFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +SheetFooter.displayName = "SheetFooter" + +const SheetTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetTitle.displayName = SheetPrimitive.Title.displayName + +const SheetDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +SheetDescription.displayName = SheetPrimitive.Description.displayName + +export { + Sheet, + SheetPortal, + SheetOverlay, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +} diff --git a/nise-replay-viewer/src/interface/components/ui/slider.tsx b/nise-replay-viewer/src/interface/components/ui/slider.tsx new file mode 100644 index 0000000..e161dae --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/slider.tsx @@ -0,0 +1,26 @@ +import * as React from "react" +import * as SliderPrimitive from "@radix-ui/react-slider" + +import { cn } from "@/lib/utils" + +const Slider = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + + + +)) +Slider.displayName = SliderPrimitive.Root.displayName + +export { Slider } diff --git a/nise-replay-viewer/src/interface/components/ui/sonner.tsx b/nise-replay-viewer/src/interface/components/ui/sonner.tsx new file mode 100644 index 0000000..1128edf --- /dev/null +++ b/nise-replay-viewer/src/interface/components/ui/sonner.tsx @@ -0,0 +1,29 @@ +import { useTheme } from "next-themes" +import { Toaster as Sonner } from "sonner" + +type ToasterProps = React.ComponentProps + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = "system" } = useTheme() + + return ( + + ) +} + +export { Toaster } diff --git a/nise-replay-viewer/src/interface/composites/Menu.tsx b/nise-replay-viewer/src/interface/composites/Menu.tsx new file mode 100644 index 0000000..ae3a4db --- /dev/null +++ b/nise-replay-viewer/src/interface/composites/Menu.tsx @@ -0,0 +1,82 @@ +import { + Menubar, + MenubarContent, + MenubarItem, + MenubarMenu, + MenubarTrigger, +} from "@/interface/components/ui/menubar"; +import { OsuRenderer } from "@/osu/OsuRenderer"; +import { state } from "@/utils"; + +export function Navbar() { + const { beatmap, mods } = state(); + return ( + +
+
+ +

+ Replay Viewer +

+
+ + + File + + { + state.setState({ aboutDialog: true }); + }} + > + About + + + + + {OsuRenderer.beatmap && ( + <> + {" "} + + Analyzer + + { + state.setState({ dataAnalysisDialog: true }); + }} + > + gRDA + + + + + )} +
+ + {beatmap && ( +
+ {mods?.map((mod) => { + return ( + + ); + })} +
+

Currently Viewing

+ +

+ {beatmap?.metadata.artist} - {beatmap?.metadata.title} +

+
+ +
+ )} +
+ ); +} diff --git a/nise-replay-viewer/src/interface/composites/about-dialog.tsx b/nise-replay-viewer/src/interface/composites/about-dialog.tsx new file mode 100644 index 0000000..7c27f8b --- /dev/null +++ b/nise-replay-viewer/src/interface/composites/about-dialog.tsx @@ -0,0 +1,27 @@ +import { Button } from "@/interface/components/ui/button"; +import { Dialog, DialogContent } from "@/interface/components/ui/dialog"; +import { Badge } from "@/interface/components/ui/badge"; +import { state } from "@/utils"; +export function AboutDialog() { + const { aboutDialog } = state(); + return ( + { + state.setState({ aboutDialog: change }); + }} + > + +
+

+ Replay Viewer +

+
+

Originally developed by Assist Games

+

With modifications to be integrated with nise.moe

+
+
+
+
+ ); +} diff --git a/nise-replay-viewer/src/interface/composites/analysis.-sheet.tsx b/nise-replay-viewer/src/interface/composites/analysis.-sheet.tsx new file mode 100644 index 0000000..8e00bae --- /dev/null +++ b/nise-replay-viewer/src/interface/composites/analysis.-sheet.tsx @@ -0,0 +1,121 @@ +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, +} from "@/interface/components/ui/sheet"; +import { Button } from "@/interface/components/ui/button"; +import { BarChart, XAxis, Bar, ResponsiveContainer } from "recharts"; +import { state } from "@/utils"; +import { gRDA } from "@/osu/Analysis"; +import { OsuRenderer } from "@/osu/OsuRenderer"; + +export function AnalysisSheet() { + const { dataAnalysisDialog, grda } = state(); + + return ( + { + state.setState({ dataAnalysisDialog: opened }); + }} + > + + + gRDA + + Most of the information provided here is forensic and can be used to + detect specific types of cheats, such as Timewarp and Relax. This + process might take up to a minute to do and collect all information. + + + + {grda && ( +
+

+ Response +

+
+

Frametime Averages:

+ + + + + + + +
Normalization rate due to mods {grda.normalizationRate}
+ + + + + + +
+ +
+

Averages:

+
+ Slider Delta Hold Average{" "} + {Math.round( + (grda.sliderDeltaHoldAverage / grda.sliderLength) * 100 + ) / 100} +
+
+ Approximated circle hold delta range ={" "} + {grda.circleExtremes.max - grda.circleExtremes.min} +
+
+ Approximated slider hold delta range ={" "} + {grda.sliderExtremes.max - grda.sliderExtremes.min} +
+
+ +
Circle | Holdtime distribution
+ + + + + + + +
Circle | Press time distribution
+ + Number(a[0]) - Number(b[0]) + )} + > + + + + +
+ )} +
+
+ ); +} diff --git a/nise-replay-viewer/src/interface/composites/helper.tsx b/nise-replay-viewer/src/interface/composites/helper.tsx new file mode 100644 index 0000000..3b886bd --- /dev/null +++ b/nise-replay-viewer/src/interface/composites/helper.tsx @@ -0,0 +1,35 @@ +import middlemouse from "/mouse.svg"; +import scroll from "/scroll.svg"; +import space from "/space.svg"; +import ctrl from "/ctrl.svg"; +import { state } from "@/utils"; + +export function Helper() { + const { replay } = state(); + + if (!replay) return <>; + + return ( +
+
+ Drag Playfield + +
+
+ Seek Beatmap + +
+
+ Pause/Play + +
+ +
+ Zoom + + +
+
+ ); + +} diff --git a/nise-replay-viewer/src/interface/composites/song-slider.tsx b/nise-replay-viewer/src/interface/composites/song-slider.tsx new file mode 100644 index 0000000..f0f9c23 --- /dev/null +++ b/nise-replay-viewer/src/interface/composites/song-slider.tsx @@ -0,0 +1,60 @@ +import { OsuRenderer } from "@/osu/OsuRenderer"; +import { Card } from "../components/ui/card"; +import { Slider } from "../components/ui/slider"; +import { state } from "@/utils"; +import { Button } from "../components/ui/button"; +import { ArrowLeft, ArrowRight, PauseIcon, PlayIcon } from "lucide-react"; + +export function SongSlider() { + const { beatmap, replay, playing, time } = state(); + if (!beatmap || !replay) { + return; + } + return ( + +
+
+

Current time

+

{new Date(time).toISOString().slice(11, 19)}

+ +
+
+ + + +
+
+ +
+ + + { + OsuRenderer.setTime(value[0]); + }} + /> +
+ ); +} diff --git a/nise-replay-viewer/src/lib/utils.ts b/nise-replay-viewer/src/lib/utils.ts new file mode 100644 index 0000000..ec79801 --- /dev/null +++ b/nise-replay-viewer/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/nise-replay-viewer/src/main.tsx b/nise-replay-viewer/src/main.tsx new file mode 100644 index 0000000..e49016f --- /dev/null +++ b/nise-replay-viewer/src/main.tsx @@ -0,0 +1,46 @@ +import p5 from "p5"; +import "./style.css"; +import "./globals.css"; +import { p, setEnv } from "./utils"; +import React from "react"; +import ReactDOM from "react-dom/client"; +import { ThemeProvider } from "./interface/components/theme-provider"; +import { App } from "./interface/App"; +import { Events, hookable } from "./hooks"; +import "@/hooks/starter"; +import { Toaster } from "./interface/components/ui/sonner"; +import { BrowserRouter as Router } from 'react-router-dom'; + +document.addEventListener("contextmenu", (event) => event.preventDefault()); +const handleWheel = hookable(Events.mouseWheel); +window.addEventListener("wheel", handleWheel, { passive: false }); + +async function main() { + new p5(async (p5Instance) => { + setEnv(p5Instance as unknown as p5); + + // Functions that should be expanded into multiple events + p.preload = hookable(Events.preload); + p.setup = hookable(Events.setup); + p.windowResized = hookable(Events.resize); + p.draw = hookable(Events.draw); + p.mousePressed = hookable(Events.mousePressed); + p.mouseDragged = hookable(Events.mouseDragged); + p.mouseReleased = hookable(Events.mouseReleased); + p.keyPressed = hookable(Events.keyPressed); + p.keyReleased = hookable(Events.keyReleased); + }, document.getElementById("app")!); +} + +main(); + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + + + + + + +); diff --git a/nise-replay-viewer/src/osu/Analysis.ts b/nise-replay-viewer/src/osu/Analysis.ts new file mode 100644 index 0000000..f2169a7 --- /dev/null +++ b/nise-replay-viewer/src/osu/Analysis.ts @@ -0,0 +1,278 @@ +import { modsFromBitmask } from "@osujs/core"; +import { LegacyReplayFrame, Score } from "osu-classes"; +import { + Circle, + StandardBeatmap, + StandardHitObject, +} from "osu-standard-stable"; + +export function getHoldAverages( + formattedPresses: { + start: number; + end: number | null; + duration: number; + object: null; + }[], + map: StandardBeatmap +) { + const circlePresses: { + start: number; + pressStart: number; + holdTime: number; + }[] = []; + const sliderPresses: { + start: number; + pressStart: number; + holdTime: number; + }[] = []; + + let circleHitAverage = 0; + let circleLength = 0; + let circleExtremes = { max: 0, min: 0 }; + + let sliderDeltaHoldAverage = 0; + let sliderLength = 0; + let sliderExtremes = { max: 0, min: 0 }; + + for (const press of formattedPresses) { + let closestObject: StandardHitObject = map.hitObjects[0]; + for (const object of map.hitObjects) { + if ( + Math.abs(press.start - object.startTime) < + Math.abs(press.start - closestObject.startTime) + ) { + closestObject = object; + } + } + press.object = closestObject as any; + if (closestObject instanceof Circle) { + circleHitAverage += press.duration; + circleLength++; + + if (press.duration < 160) { + circlePresses.push({ + start: closestObject.startTime, + pressStart: press.start, + holdTime: press.duration, + }); + if (press.duration > circleExtremes.max) { + circleExtremes.max = press.duration; + } + if (press.duration < circleExtremes.min) { + circleExtremes.min = press.duration; + } + } + } + + if ((closestObject as any).duration) { + if (press.duration && (closestObject as any).duration) { + let sval = press.duration - (closestObject as any).duration; + sliderDeltaHoldAverage += sval; + sliderLength++; + + sliderPresses.push({ + start: closestObject.startTime, + pressStart: press.start, + holdTime: sval, + }); + + if (sval > sliderExtremes.max) { + sliderExtremes.max = sval; + } + if (sval < sliderExtremes.min) { + sliderExtremes.min = sval; + } + } + } + } + + return { + circlePresses, + sliderPresses, + circleLength, + sliderDeltaHoldAverage, + circleHitAverage, + sliderLength, + circleExtremes, + sliderExtremes, + }; +} + +export function getPresses(score: Score) { + let frameTimes: Record = {}; + let moddedFrameTimes: Record = {}; + const mods = modsFromBitmask(score.info.rawMods as number); + let normalizationRate = 1; + if (mods.includes("DOUBLE_TIME") || mods.includes("NIGHT_CORE")) { + normalizationRate = 1.5; + } + if (mods.includes("HALF_TIME")) { + normalizationRate = 0.75; + } + + const presses: { start: number; end: number | null; tempEnd: number }[] = [ + { start: 0, end: 0, tempEnd: 0 }, + ]; + + const presses2: { start: number; end: number | null; tempEnd: number }[] = [ + { start: 0, end: 0, tempEnd: 0 }, + ]; + + score.replay?.frames.forEach((_frame) => { + let frame = _frame as LegacyReplayFrame; + if (!frameTimes[frame.interval]) { + frameTimes[frame.interval] = 1; + } else { + frameTimes[frame.interval] += 1; + } + + if (!moddedFrameTimes[Math.round(frame.interval / normalizationRate)]) { + moddedFrameTimes[Math.round(frame.interval / normalizationRate)] = 1; + } else { + moddedFrameTimes[Math.round(frame.interval / normalizationRate)] += 1; + } + + const lastpress = presses[presses.length - 1]; + if (frame.mouseLeft) { + if (lastpress.end !== null) { + presses.push({ + start: frame.startTime, + end: null, + tempEnd: frame.startTime, + }); + } else { + lastpress.tempEnd = frame.startTime; + } + } else { + if (lastpress.end === null) { + lastpress.end = frame.startTime; + } + } + + const lastpress2 = presses2[presses2.length - 1]; + if (frame.mouseRight) { + if (lastpress2.end !== null) { + presses2.push({ + start: frame.startTime, + end: null, + tempEnd: frame.startTime, + }); + } else { + lastpress2.tempEnd = frame.startTime; + } + } else { + if (lastpress2.end === null) { + lastpress2.end = frame.startTime; + } + } + }); + + return { frameTimes, moddedFrameTimes, presses, presses2, normalizationRate }; +} + +export function getFormattedPresses( + presses: { + start: number; + end: number | null; + tempEnd: number; + }[], + presses2: { + start: number; + end: number | null; + tempEnd: number; + }[], + map: StandardBeatmap +) { + const allPresses = [...presses, ...presses2]; + + const formattedPresses = allPresses.map((press) => ({ + start: press.start, + end: press.end, + duration: press.end! - press.start, + object: null, + })); + + let joined: any = []; + map.hitObjects.forEach((object: any) => { + (joined as any).push({ + start: object.startTime, + end: null, + sduration: (object as any).duration, + }); + }); + + formattedPresses.forEach((object) => { + (joined as any).push({ + start: object.start, + end: object.end, + duration: object.duration, + }); + }); + formattedPresses.sort((a, b) => a.start - b.start); + joined.sort((a: any, b: any) => a.start - b.start); + return { formattedPresses, joined }; +} + +export function baseRound( + x: number, + prec: number = 2, + base: number = 0.05 +): number { + return Number((Math.round(x / base) * base).toFixed(prec)); +} + +export function gRDA(score: Score, map: StandardBeatmap) { + const { frameTimes, moddedFrameTimes, normalizationRate, presses, presses2 } = + getPresses(score); + + const { formattedPresses } = getFormattedPresses(presses, presses2, map); + + const { + circlePresses, + sliderPresses, + circleLength, + sliderDeltaHoldAverage, + circleHitAverage, + sliderLength, + circleExtremes, + sliderExtremes, + } = getHoldAverages(formattedPresses, map); + + const holdCircleDistributionGraph: Record = {}; + + for (const press of circlePresses) { + const normalizedTime = baseRound(press.holdTime, 1, 3); + if (!holdCircleDistributionGraph[normalizedTime]) { + holdCircleDistributionGraph[normalizedTime] = 1; + } else { + holdCircleDistributionGraph[normalizedTime] += 1; + } + } + + const pressCircleDistributionGraph: Record = {}; + + for (const press of circlePresses) { + const normalizedTime = baseRound(press.pressStart - press.start, 1, 3); + if (!pressCircleDistributionGraph[normalizedTime]) { + pressCircleDistributionGraph[normalizedTime] = 1; + } else { + pressCircleDistributionGraph[normalizedTime] += 1; + } + } + + return { + frameTimes, + moddedFrameTimes, + normalizationRate, + holdCircleDistributionGraph, + pressCircleDistributionGraph, + sliderPresses, + circlePresses, + sliderLength, + circleLength, + sliderDeltaHoldAverage, + circleHitAverage, + circleExtremes, + sliderExtremes, + }; +} diff --git a/nise-replay-viewer/src/osu/Drawer.ts b/nise-replay-viewer/src/osu/Drawer.ts new file mode 100644 index 0000000..3b3c7f0 --- /dev/null +++ b/nise-replay-viewer/src/osu/Drawer.ts @@ -0,0 +1,299 @@ +import { Vector2 } from "osu-classes"; +import { Md5 } from "ts-md5"; +import p5 from "p5"; +import { loadImageAsync } from "@/utils"; + +export class Drawer { + private static imageCache: Record = {}; + static images = { + cursor: undefined as any as p5.Image, + cursortrail: undefined as any as p5.Image, + hitcircle: undefined as any as p5.Image, + hitcircleoverlay: undefined as any as p5.Image, + radix: undefined as any as p5.Image, + sliderfollowcircle: undefined as any as p5.Image, + sliderb0: undefined as any as p5.Image, + default0: undefined as any as p5.Image, + default1: undefined as any as p5.Image, + default2: undefined as any as p5.Image, + default3: undefined as any as p5.Image, + default4: undefined as any as p5.Image, + default5: undefined as any as p5.Image, + default6: undefined as any as p5.Image, + default7: undefined as any as p5.Image, + default8: undefined as any as p5.Image, + default9: undefined as any as p5.Image, + }; + private static p: p5; + + static setP(_p: p5) { + this.p = _p; + } + + static async loadDefaultImages() { + for (const imageName of Object.keys(Drawer.images)) { + Drawer.images[imageName as keyof typeof Drawer.images] = + await loadImageAsync(`/${imageName}.png`); + } + } + + static setImages(images: typeof this.images) { + this.images = images; + } + + static setDrawingOpacity(opacity: number) { + //@ts-ignore + this.p.drawingContext.globalAlpha = opacity; + } + + static drawCircleJudgement( + position: Vector2, + radius: number, + judgement: string + ) { + Drawer.p.push(); + Drawer.p.strokeWeight(2); + if (judgement === "OK") { + Drawer.p.stroke(`rgb(106, 176, 76)`); + Drawer.p.fill(`rgb(106, 176, 76)`); + } + if (judgement === "MEH") { + Drawer.p.stroke(`rgb(241, 196, 15)`); + Drawer.p.fill(`rgb(241, 196, 15)`); + } + if (judgement === "MISS") { + Drawer.p.stroke(`rgb(231, 76, 60)`); + Drawer.p.fill(`rgb(231, 76, 60)`); + } + if (judgement !== "GREAT") { + Drawer.p.circle(position.x, position.y, radius * 2); + } + Drawer.p.pop(); + } + + static drawSliderFollowPoint(position: Vector2, radius: number) { + Drawer.p.image( + this.images.sliderfollowcircle, + position.x, + position.y, + radius * 2, + radius * 2 + ); + Drawer.p.push(); + Drawer.p.fill(255, 255, 255, 18); + Drawer.p.circle(position.x, position.y, radius * 4); + Drawer.p.pop(); + } + + static drawHitCircle(position: Vector2, radius: number, comboNumber: number) { + Drawer.p.push(); + Drawer.p.noStroke(); + Drawer.p.fill(160); + Drawer.p.image( + this.images.hitcircle, + position.x, + position.y, + radius * 2, + radius * 2 + ); + Drawer.p.image( + this.images.hitcircleoverlay, + position.x, + position.y, + radius * 2, + radius * 2 + ); + this.drawNumberWithSprites( + comboNumber + 1, + new Vector2(position.x - 0.5, position.y), + radius * 0.4 + ); + + Drawer.p.pop(); + } + + static drawApproachCircle( + position: Vector2, + radius: number, + arScale: number + ) { + if (arScale == 1) return; + Drawer.p.push(); + Drawer.p.noFill(); + Drawer.p.stroke("white"); + Drawer.p.strokeWeight(3); + Drawer.p.circle(position.x, position.y, radius * 2 * arScale); + Drawer.p.pop(); + } + + static drawSliderBody(origin: Vector2, path: Vector2[], radius: number) { + Drawer.p.push(); + + const cacheKey = Md5.hashStr(JSON.stringify(path) + JSON.stringify(radius)); + if (!this.imageCache[cacheKey]) { + const g = Drawer.p.createGraphics(512 * 4, 384 * 4); + g.scale(2); + g.translate(512 - 256, 384 - 192); + //@ts-ignore + const ctx = g.drawingContext; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + g.translate(origin.x, origin.y); + g.noFill(); + + g.strokeWeight(radius * 2 - 10); + + g.stroke(255); + g.beginShape(); + for (const node of path) { + g.vertex(node.x, node.y); + } + g.endShape(); + + g.strokeWeight(radius * 2 - 17); + g.stroke(10); + g.beginShape(); + for (const node of path) { + g.vertex(node.x, node.y); + } + + g.endShape(); + + for (let i = 0; i < radius * 2 - 17; i += 2) { + g.strokeWeight(radius * 2 - 17 - i); + g.stroke(Math.round((i / (radius * 2 - 17)) * 45)); + g.beginShape(); + for (const node of path) { + g.vertex(node.x, node.y); + } + + g.endShape(); + } + + this.imageCache[cacheKey] = g; + } + Drawer.p.imageMode(Drawer.p.CORNER); + Drawer.p.image(this.imageCache[cacheKey], -256, -192, 512 * 2, 384 * 2); + + Drawer.p.pop(); + } + + static drawCursorPath( + path: { + position: Vector2; + button: { + mouseLeft1: boolean; + mouseLeft2: boolean; + mouseRight1: boolean; + mouseRight2: boolean; + }; + }[], + cursor: { + position: Vector2; + button: { + mouseLeft1: boolean; + mouseLeft2: boolean; + mouseRight1: boolean; + mouseRight2: boolean; + }; + } + ) { + Drawer.p.push(); + //@ts-ignore + const ctx = Drawer.p.drawingContext; + ctx.lineCap = "round"; + ctx.lineJoin = "round"; + Drawer.p.noFill(); + + Drawer.p.push(); + Drawer.p.strokeWeight(2.5); + Drawer.p.stroke("black"); + for (let i = 1; i < path.length; i++) { + const lastFrame = path[i - 1]; + const frame = path[i]; + + Drawer.p.line( + lastFrame.position.x, + lastFrame.position.y, + frame.position.x, + frame.position.y + ); + } + + Drawer.p.pop(); + Drawer.p.strokeWeight(1.5); + Drawer.p.stroke("white"); + + for (let i = 1; i < path.length; i++) { + const lastFrame = path[i - 1]; + const frame = path[i]; + Drawer.p.stroke("white"); + + if (lastFrame.button.mouseLeft1 || lastFrame.button.mouseLeft2) { + Drawer.p.stroke("#BB6BD9"); + } + if (lastFrame.button.mouseRight1 || lastFrame.button.mouseRight2) { + Drawer.p.stroke("#F2994A"); + } + if (lastFrame.button.mouseLeft1 && lastFrame.button.mouseRight1) { + Drawer.p.stroke("red"); + } + Drawer.p.line( + lastFrame.position.x, + lastFrame.position.y, + frame.position.x, + frame.position.y + ); + } + + if (cursor.position) + Drawer.p.image( + this.images.cursor, + cursor.position.x, + cursor.position.y, + 55, + 55 + ); + + Drawer.p.pop(); + } + static drawNumberWithSprites( + number: number, + position: Vector2, + size: number + ) { + Drawer.p.push(); + Drawer.p.imageMode(Drawer.p.CORNER); + const digits = number.toString().split(""); + const digitWidth = size; + const digitHeight = size * 1.2; + const digitSpacing = -size * 0.1; + const totalWidth = digits.length * (digitWidth + digitSpacing); + const x = position.x - totalWidth / 2; + const y = position.y - digitHeight / 2; + digits.forEach((digit, index) => { + const indexer = `default${digit}`; + const image = this.images[indexer as keyof typeof this.images]; + Drawer.p.image( + image, + x + index * (digitWidth + digitSpacing), + y, + digitWidth, + digitHeight + ); + }); + Drawer.p.pop(); + } + static drawField() { + Drawer.p.noFill(); + Drawer.p.stroke(255, 255, 255, 60); + Drawer.p.rect(0, 0, 512, 384, 4); + } + + static beginDrawing() { + Drawer.p.push(); + } + static endDrawing() { + Drawer.p.pop(); + } +} diff --git a/nise-replay-viewer/src/osu/OsuRenderer.ts b/nise-replay-viewer/src/osu/OsuRenderer.ts new file mode 100644 index 0000000..c7704bf --- /dev/null +++ b/nise-replay-viewer/src/osu/OsuRenderer.ts @@ -0,0 +1,413 @@ +import {HitResult, LegacyReplayFrame, Score, Vector2} from "osu-classes"; +import { BeatmapDecoder, BeatmapEncoder } from "osu-parsers"; +import { + Circle, + Slider, + Spinner, + StandardBeatmap, + StandardHardRock, + StandardHitObject, + StandardModCombination, + StandardRuleset, +} from "osu-standard-stable"; +import { Drawer } from "./Drawer"; +import { Vec2 } from "@osujs/math"; +import { clamp, getBeatmap, getReplay } from "@/utils"; +import EventEmitter from "eventemitter3"; + +export enum OsuRendererEvents { + UPDATE = "UPDATE", + LOAD = "LOAD", + PLAY = "PLAY", + TIME = "TIME", +} + +export class OsuRendererBridge extends EventEmitter { + constructor() { + super(); + } +} + +export class OsuRenderer { + private static preempt: number; + private static fadeIn: number; + private static lastRender: number = Date.now(); + + static playing: boolean = false; + + static event = new OsuRendererBridge(); + + static time: number = 0; + static beatmap: StandardBeatmap; + static og_beatmap: StandardBeatmap; + static replay: Score; + static og_replay_mods: StandardModCombination; + static forceHR: boolean | undefined = undefined; + + static loaded: boolean = false; + + static pathWindow: number = 500; + + static purge() { + this.replay = undefined as any; + this.beatmap = undefined as any; + } + + static render() { + if (!this.beatmap || !this.replay) return; + + if (this.time >= this.replay.replay!.length - 500) + this.time = this.replay.replay!.length - 500; + + for (let i = this.beatmap.hitObjects.length - 1; i >= 0; i--) { + this.renderObject(this.beatmap.hitObjects[i]); + } + + if (this.playing) { + this.setTime(this.time + (Date.now() - this.lastRender)); + } + + this.lastRender = Date.now(); + + this.renderPath(); + Drawer.drawField(); + } + + static getOptions() { + return { + replay: this.replay, + mods: this.replay.info.mods?.all, + beatmap: this.og_beatmap, + }; + } + + static getCurrentDifficulty() { + return { + AR: OsuRenderer.og_beatmap?.difficulty?.approachRate, + CS: OsuRenderer.og_beatmap?.difficulty?.circleSize, + OD: OsuRenderer.og_beatmap?.difficulty?.overallDifficulty, + }; + } + + static setMetadata({ AR, CS, OD }: { AR: number; CS: number; OD: number }) { + this.og_beatmap.difficulty.approachRate = AR; + this.og_beatmap.difficulty.circleSize = CS; + this.og_beatmap.difficulty.overallDifficulty = OD; + const tempClone = this.og_beatmap.clone(); + let sendMods = this.replay.info.mods as StandardModCombination; + const hasHardrock = sendMods.all.some((e) => e instanceof StandardHardRock); + + if (this.forceHR !== undefined) { + if (hasHardrock !== this.forceHR) { + this.replay.replay?.frames.forEach((frame) => { + const f = frame as LegacyReplayFrame; + f.position = new Vector2(f.position.x, 384 - f.position.y); + }); + } + if (this.forceHR) { + if (!hasHardrock) { + //@ts-ignore + sendMods._mods.push(new StandardHardRock()); + } + } else { + //@ts-ignore + sendMods._mods = sendMods._mods.filter( + //@ts-ignore + (e) => !(e instanceof StandardHardRock) + ); + } + } + + this.beatmap = this.recreateBeatmap(tempClone, sendMods); + // GameplayAnalyzer.createBucket(this.replay, this.beatmap); + + let fadeIn: number; + let preempt: number; + if (this.beatmap!.difficulty.approachRate <= 5) { + fadeIn = 800 + (400 * (5 - this.beatmap!.difficulty.approachRate)) / 5; + preempt = 1200 + (600 * (5 - this.beatmap!.difficulty.approachRate)) / 5; + } else { + fadeIn = 800 - (500 * (this.beatmap!.difficulty.approachRate - 5)) / 5; + preempt = 1200 - (750 * (this.beatmap!.difficulty.approachRate - 5)) / 5; + } + this.preempt = preempt; + this.fadeIn = fadeIn; + this.event.emit(OsuRendererEvents.UPDATE); + } + + static setPlaying(state: boolean) { + this.playing = state; + this.event.emit(OsuRendererEvents.PLAY); + } + + static refreshMetadata() { + OsuRenderer.setMetadata({ + AR: OsuRenderer.og_beatmap.difficulty.approachRate, + CS: OsuRenderer.og_beatmap.difficulty.circleSize, + OD: OsuRenderer.og_beatmap.difficulty.overallDifficulty, + }); + } + + static async loadReplayFromUrl(url: string) { + OsuRenderer.purge(); + + const response = await fetch(url, { + headers: { + 'X-NISE-REPLAY': '20240303' + } + }); + + const data = await response.json(); + + const { beatmap, replay, mods } = data; + + const i_replay = await getReplay(replay); + i_replay.info.rawMods = mods; + i_replay.info.mods = new StandardModCombination(mods); + + const i_beatmap = await getBeatmap(beatmap, i_replay); + + OsuRenderer.setOptions(i_beatmap, i_replay); + this.event.emit(OsuRendererEvents.LOAD); + } + + static setOptions(beatmap: StandardBeatmap, replay: Score) { + this.forceHR = undefined; + this.replay = replay; + this.beatmap = beatmap; + this.og_beatmap = beatmap.clone(); + this.og_replay_mods = replay.info.mods?.clone() as StandardModCombination; + this.setMetadata({ + AR: this.beatmap.difficulty.approachRate, + CS: this.beatmap.difficulty.circleSize, + OD: this.beatmap.difficulty.overallDifficulty, + }); + } + + static setTime(time: number) { + this.time = clamp(time, 0, OsuRenderer.replay.replay?.length || 0); + this.event.emit(OsuRendererEvents.TIME); + } + + private static renderObject(hitObject: StandardHitObject) { + if (hitObject instanceof Circle) { + this.renderCircle(hitObject); + } + + if (hitObject instanceof Slider) { + this.renderSlider(hitObject); + } + } + + private static calculateEffects(hitObject: StandardHitObject) { + let vEndTime = hitObject.startTime; + + if (hitObject instanceof Slider || hitObject instanceof Spinner) { + vEndTime = hitObject.endTime + 25; + } + + const fadeOut = Math.max( + 0.0, + (this.time - vEndTime) / hitObject.hitWindows.windowFor(HitResult.Meh) + ); + + let opacity = Math.max( + 0.0, + Math.min( + 1.0, + Math.min( + 1.0, + (this.time - hitObject.startTime + this.preempt) / this.fadeIn + ) - fadeOut + ) + ); + + const arScale = Math.max( + 1, + ((hitObject.startTime - this.time) / this.preempt) * 3.0 + 1.0 + ); + + let visible = + this.time > hitObject.startTime - this.preempt && + this.time < vEndTime + hitObject.hitWindows.windowFor(HitResult.Meh); + + if (hitObject instanceof Slider && this.time > hitObject.endTime) { + opacity -= (this.time - hitObject.endTime) / 25; + } + return { + opacity, + arScale, + visible, + }; + } + + private static renderCircle(hitObject: Circle) { + if (hitObject.startTime > this.time + 10000) return; + const { arScale, opacity, visible } = this.calculateEffects(hitObject); + + if (!visible) return; + Drawer.beginDrawing(); + + Drawer.setDrawingOpacity(opacity); + + Drawer.drawApproachCircle( + hitObject.stackedStartPosition, + hitObject.radius, + arScale + ); + Drawer.drawHitCircle( + hitObject.stackedStartPosition, + hitObject.radius, + hitObject.currentComboIndex + ); + + // if (GameplayAnalyzer.renderJudgements[hitObject.startTime]) { + // Drawer.setDrawingOpacity(opacity / 2); + // + // Drawer.drawCircleJudgement( + // hitObject.stackedStartPosition, + // hitObject.radius, + // GameplayAnalyzer.renderJudgements[hitObject.startTime] + // ); + // } + Drawer.endDrawing(); + return arScale; + } + + private static renderSlider(hitObject: Slider) { + if (hitObject.endTime > this.time + 10000) return; + + const { arScale, opacity, visible } = this.calculateEffects(hitObject); + + if (!visible) return; + Drawer.beginDrawing(); + Drawer.setDrawingOpacity(opacity * 0.8); + + Drawer.drawSliderBody( + hitObject.stackedStartPosition, + hitObject.path.path, + hitObject.radius + ); + Drawer.setDrawingOpacity(opacity); + + Drawer.drawApproachCircle( + hitObject.stackedStartPosition, + hitObject.radius, + arScale + ); + Drawer.drawHitCircle( + hitObject.stackedStartPosition, + hitObject.radius, + hitObject.currentComboIndex + ); + + let progress = (this.time - hitObject.startTime) / hitObject.duration; + let position = hitObject.stackedStartPosition.add( + hitObject.path.curvePositionAt(progress, hitObject.repeats + 1) + ); + + if (hitObject.repeats == 0) { + position = hitObject.stackedStartPosition.add( + hitObject.path.positionAt(progress) + ); + } + + let sliderPos = new Vector2(position.x, position.y); + + if (this.time > hitObject.startTime && this.time < hitObject.endTime) { + Drawer.drawSliderFollowPoint(sliderPos, hitObject.radius); + } + + // if (GameplayAnalyzer.renderJudgements[hitObject.startTime]) { + // Drawer.setDrawingOpacity(opacity / 2); + + // Drawer.drawCircleJudgement( + // hitObject.stackedStartPosition, + // hitObject.radius, + // GameplayAnalyzer.renderJudgements[hitObject.startTime] + // ); + // } + Drawer.endDrawing(); + return arScale; + } + + private static renderPath() { + const frames = this.replay.replay!.frames as LegacyReplayFrame[]; + const renderFrames: { + position: Vector2; + button: { + mouseLeft1: boolean; + mouseLeft2: boolean; + mouseRight1: boolean; + mouseRight2: boolean; + }; + }[] = []; + let lastFrame: LegacyReplayFrame | undefined; + let cursorPushed: any = false; + for (const frame of frames) { + if (frame.startTime > this.time) { + if (!cursorPushed) + cursorPushed = { + position: this.interpolateReplayPosition( + lastFrame ? lastFrame : frame, + frame, + this.time + ), + button: { + mouseLeft1: frame.mouseLeft1, + mouseLeft2: frame.mouseLeft2, + mouseRight1: frame.mouseRight1, + mouseRight2: frame.mouseRight2, + }, + }; + if (frame.startTime > this.time + this.pathWindow) break; + } + if (frame.startTime < this.time - this.pathWindow) { + continue; + } + lastFrame = frame; + // renderFrames.push({ + // position: frame.position, + // button: { + // mouseLeft1: frame.mouseLeft1, + // mouseLeft2: frame.mouseLeft2, + // mouseRight1: frame.mouseRight1, + // mouseRight2: frame.mouseRight2, + // }, + // }); + } + + Drawer.drawCursorPath(renderFrames, cursorPushed); + + return cursorPushed; + } + + private static interpolateReplayPosition( + fA: LegacyReplayFrame, + fB: LegacyReplayFrame, + time: number + ): Vector2 { + if (fB.startTime === fA.startTime) { + return fA.position; + } else { + const p = (time - fA.startTime) / (fB.startTime - fA.startTime); + const { x, y } = Vec2.interpolate(fA.position, fB.position, p); + return new Vector2(x, y); + } + } + + private static recreateBeatmap( + beatmap: StandardBeatmap, + mods: StandardModCombination + ) { + const beatmapDecoder = new BeatmapDecoder(); + const beatmapEncoder = new BeatmapEncoder(); + const ruleset = new StandardRuleset(); + + const bp = beatmapDecoder.decodeFromString( + beatmapEncoder.encodeToString(beatmap) + ); + return ruleset.applyToBeatmapWithMods(bp, mods as StandardModCombination); + } + +} diff --git a/nise-replay-viewer/src/renderer.ts b/nise-replay-viewer/src/renderer.ts new file mode 100644 index 0000000..ace565d --- /dev/null +++ b/nise-replay-viewer/src/renderer.ts @@ -0,0 +1,50 @@ +import { Vector } from "p5"; +import { p, state } from "./utils"; +import { OsuRenderer, OsuRendererEvents } from "./osu/OsuRenderer"; +import { Drawer } from "./osu/Drawer"; +import { toast } from "sonner"; + +export class Renderer { + static mouse: Vector; + static OsuRenderer: OsuRenderer = OsuRenderer; + + static async setup() { + Renderer.registerEvents(); + Drawer.setP(p); + + await Drawer.loadDefaultImages(); + } + + static draw() { + if (!OsuRenderer.beatmap) return; + + OsuRenderer.render(); + p.circle(this.mouse.x, this.mouse.y, 25); + } + + static registerEvents() { + // Sync UI with datapath classes + OsuRenderer.event.on(OsuRendererEvents.UPDATE, () => { + const options = OsuRenderer.getOptions(); + state.setState({ + beatmap: options.beatmap, + replay: options.replay, + mods: options.mods, + }); + }); + + OsuRenderer.event.on(OsuRendererEvents.LOAD, () => { + toast(`Successfully loaded replay!`); + }); + OsuRenderer.event.on(OsuRendererEvents.PLAY, () => { + state.setState({ + playing: OsuRenderer.playing, + }); + }); + OsuRenderer.event.on(OsuRendererEvents.TIME, () => { + state.setState({ + time: OsuRenderer.time, + }); + }); + } +} diff --git a/nise-replay-viewer/src/style.css b/nise-replay-viewer/src/style.css new file mode 100644 index 0000000..6b458e3 --- /dev/null +++ b/nise-replay-viewer/src/style.css @@ -0,0 +1,35 @@ +#app { + margin:0; + padding: 0; + position: absolute; + z-index: -1; +} + +#root{ +} + +body{ + margin:0; + overflow: hidden; +} + + /* width */ + ::-webkit-scrollbar { + width: 6px; + } + + /* Track */ + ::-webkit-scrollbar-track { + background: #f1f1f10a; + } + + /* Handle */ + ::-webkit-scrollbar-thumb { + background: #88888852; + border-radius: 5px; + } + + /* Handle on hover */ + ::-webkit-scrollbar-thumb:hover { + background: #555; + } \ No newline at end of file diff --git a/nise-replay-viewer/src/tooling/brush.ts b/nise-replay-viewer/src/tooling/brush.ts new file mode 100644 index 0000000..79ccce3 --- /dev/null +++ b/nise-replay-viewer/src/tooling/brush.ts @@ -0,0 +1,15 @@ +import { Tool } from "./tool"; +import { Singleton } from "@/decorators/singleton"; + +@Singleton +export class BrushTool extends Tool { + mousePressed(): void { + throw new Error("Method not implemented."); + } + mouseReleased(): void { + throw new Error("Method not implemented."); + } + tick(): void { + throw new Error("Method not implemented."); + } +} diff --git a/nise-replay-viewer/src/tooling/tool.ts b/nise-replay-viewer/src/tooling/tool.ts new file mode 100644 index 0000000..771d44e --- /dev/null +++ b/nise-replay-viewer/src/tooling/tool.ts @@ -0,0 +1,5 @@ +export abstract class Tool { + abstract mousePressed(): void; + abstract mouseReleased(): void; + abstract tick(): void; +} diff --git a/nise-replay-viewer/src/utils.ts b/nise-replay-viewer/src/utils.ts new file mode 100644 index 0000000..bb6958b --- /dev/null +++ b/nise-replay-viewer/src/utils.ts @@ -0,0 +1,84 @@ +import { BeatmapDecoder } from "osu-parsers"; +import { ScoreDecoder } from "../osu-parsers"; +import { StandardRuleset, StandardBeatmap } from "osu-standard-stable"; + +import { IMod, Score } from "osu-classes"; +import p5, { Image } from "p5"; +import { create } from "zustand"; + +const ruleset = new StandardRuleset(); +const scoreDecoder = new ScoreDecoder(); +const beatmapDecoder = new BeatmapDecoder(); + +export async function getReplay(buffer: ArrayBuffer) { + const repl = await scoreDecoder.decodeFromBuffer(buffer); + repl.info.ruleset = ruleset; + return repl; +} + +export async function getBeatmap(mapText: string, scoreBase: Score) { + const map = beatmapDecoder.decodeFromString(mapText); + + const score = scoreBase.info; + score.accuracy = + (score.count300 + score.count100 / 3 + score.count50 / 6) / + (score.count300 + score.count100 + score.count50 + score.countMiss); + + return ruleset.applyToBeatmap(map); +} + +export async function loadImageAsync(image: string): Promise { + return new Promise((res) => { + p.loadImage(image, (img) => { + res(img); + }); + }); +} + +export function clamp(num: number, min: number, max: number) { + if (num > max) return max; + if (num < min) return min; + return num +} + +export const state = create<{ + beatmap: StandardBeatmap | null; + replay: Score | null; + metadataEditorDialog: boolean; + openDialog: boolean; + saveDialog: boolean; + dataAnalysisDialog: boolean; + achivementsDialog: boolean; + aboutDialog: boolean; + grda: any; + tool: "cursor" | "brush" | "advanced" | "smoother"; + mods: IMod[] | null; + playing: boolean; + time: number; +}>(() => ({ + metadataEditorDialog: false, + openDialog: false, + saveDialog: false, + aboutDialog: false, + achivementsDialog: false, + dataAnalysisDialog: false, + beatmap: null, + replay: null, + grda: null, + tool: "cursor", + mods: null, + playing: false, + time: 0, +})); + +state.subscribe((newState) => { + if (newState.beatmap) { + document.title = `${newState.beatmap.metadata.artist} - ${newState.beatmap.metadata.titleUnicode} | Replay Inspector` + } +}) + +export let p: p5; + +export function setEnv(_p: p5) { + p = _p; +} diff --git a/nise-replay-viewer/tailwind.config.js b/nise-replay-viewer/tailwind.config.js new file mode 100644 index 0000000..0377ea1 --- /dev/null +++ b/nise-replay-viewer/tailwind.config.js @@ -0,0 +1,76 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: ["class"], + content: [ + './pages/**/*.{ts,tsx}', + './components/**/*.{ts,tsx}', + './app/**/*.{ts,tsx}', + './src/**/*.{ts,tsx}', + ], + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: 0 }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: 0 }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +} \ No newline at end of file diff --git a/nise-replay-viewer/tsconfig.json b/nise-replay-viewer/tsconfig.json new file mode 100644 index 0000000..f50d4b4 --- /dev/null +++ b/nise-replay-viewer/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "strict": true, + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "types": ["vite/client"], + "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["./src", "node_modules/@types/p5/index.d.ts"] +} diff --git a/nise-replay-viewer/vite.config.ts b/nise-replay-viewer/vite.config.ts new file mode 100644 index 0000000..cf45b55 --- /dev/null +++ b/nise-replay-viewer/vite.config.ts @@ -0,0 +1,12 @@ +import path from "path"; +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [react()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, +}); diff --git a/nise-replay-viewer/yarn.lock b/nise-replay-viewer/yarn.lock new file mode 100644 index 0000000..f2aa269 --- /dev/null +++ b/nise-replay-viewer/yarn.lock @@ -0,0 +1,2011 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@babel/code-frame@^7.22.13": + version "7.22.13" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz" + integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== + dependencies: + "@babel/highlight" "^7.22.13" + chalk "^2.4.2" + +"@babel/compat-data@^7.22.9": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz" + integrity sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ== + +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz" + integrity sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.3" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helpers" "^7.23.2" + "@babel/parser" "^7.23.3" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.3" + "@babel/types" "^7.23.3" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz" + integrity sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg== + dependencies: + "@babel/types" "^7.23.3" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz" + integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.15" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-plugin-utils@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz" + integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== + +"@babel/helpers@^7.23.2": + version "7.23.2" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz" + integrity sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.2" + "@babel/types" "^7.23.0" + +"@babel/highlight@^7.22.13": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz" + integrity sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw== + +"@babel/plugin-transform-react-jsx-self@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz" + integrity sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-react-jsx-source@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz" + integrity sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/runtime@^7.1.2", "@babel/runtime@^7.13.10", "@babel/runtime@^7.23.5": + version "7.23.8" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz" + integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.23.2", "@babel/traverse@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz" + integrity sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.23.3" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.3" + "@babel/types" "^7.23.3" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz" + integrity sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@floating-ui/core@^1.5.3": + version "1.5.3" + resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.3.tgz" + integrity sha512-O0WKDOo0yhJuugCx6trZQj5jVJ9yR0ystG2JaNAemYUWce+pmM6WUEFIibnWyEJKdrDxhm75NoSRME35FNaM/Q== + dependencies: + "@floating-ui/utils" "^0.2.0" + +"@floating-ui/dom@^1.5.4": + version "1.5.4" + resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.4.tgz" + integrity sha512-jByEsHIY+eEdCjnTVu+E3ephzTOzkQ8hgUfGwos+bg7NlH33Zc5uO+QHz1mrQUOgIKKDD1RtS201P9NvAfq3XQ== + dependencies: + "@floating-ui/core" "^1.5.3" + "@floating-ui/utils" "^0.2.0" + +"@floating-ui/react-dom@^2.0.0": + version "2.0.6" + resolved "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.6.tgz" + integrity sha512-IB8aCRFxr8nFkdYZgH+Otd9EVQPJoynxeFRGTB8voPoZMRWo8XjYuCRgpI1btvuKY69XMiLnW+ym7zoBHM90Rw== + dependencies: + "@floating-ui/dom" "^1.5.4" + +"@floating-ui/utils@^0.2.0": + version "0.2.1" + resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz" + integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q== + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@next/env@14.1.0": + version "14.1.0" + resolved "https://registry.npmjs.org/@next/env/-/env-14.1.0.tgz" + integrity sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw== + +"@next/swc-linux-x64-gnu@14.1.0": + version "14.1.0" + resolved "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.0.tgz" + integrity sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ== + +"@next/swc-linux-x64-musl@14.1.0": + version "14.1.0" + resolved "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.0.tgz" + integrity sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@osujs/core@^0.0.6": + version "0.0.6" + resolved "https://registry.npmjs.org/@osujs/core/-/core-0.0.6.tgz" + integrity sha512-hnxdcjcMylS95NMtoAYwZZxFMsDkZDKAJk2nK6OCHwPXLaaW4DoVBdBFEoWy1VuuR9yAP8b1yATZtsLeaCH2mA== + +"@osujs/math@^0.0.4", "@osujs/math@0.0.4": + version "0.0.4" + resolved "https://registry.npmjs.org/@osujs/math/-/math-0.0.4.tgz" + integrity sha512-4zIvKjsS2ONVQIifRoJLT0BH3YldkOW88AG5yOZ8thjRG9Btdd1l9syAQWSDUchp7t3S9Ducquhctyv2v5lwiA== + +"@radix-ui/number@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz" + integrity sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/primitive@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz" + integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-arrow@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz" + integrity sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + +"@radix-ui/react-collection@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz" + integrity sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + +"@radix-ui/react-compose-refs@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz" + integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-context-menu@^2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.1.5.tgz" + integrity sha512-R5XaDj06Xul1KGb+WP8qiOh7tKJNz2durpLBXAGZjSVtctcRFCuEvy2gtMwRJGePwQQE5nV77gs4FwRi8T+r2g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-menu" "2.0.6" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-context@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz" + integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-dialog@^1.0.5": + version "1.0.5" + resolved "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz" + integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + +"@radix-ui/react-direction@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz" + integrity sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-dismissable-layer@1.0.5": + version "1.0.5" + resolved "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz" + integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-escape-keydown" "1.0.3" + +"@radix-ui/react-focus-guards@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz" + integrity sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-focus-scope@1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz" + integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-id@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz" + integrity sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/react-label@^2.0.2": + version "2.0.2" + resolved "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.0.2.tgz" + integrity sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + +"@radix-ui/react-menu@2.0.6": + version "2.0.6" + resolved "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.6.tgz" + integrity sha512-BVkFLS+bUC8HcImkRKPSiVumA1VPOOEC5WBMiT+QAVsPzW1FJzI9KnqgGxVDPBcql5xXrHkD3JOVoXWEXD8SYA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-popper" "1.1.3" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-roving-focus" "1.0.4" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-callback-ref" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + +"@radix-ui/react-menubar@^1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.0.4.tgz" + integrity sha512-bHgUo9gayKZfaQcWSSLr++LyS0rgh+MvD89DE4fJ6TkGHvjHgPaBZf44hdka7ogOxIOdj9163J+5xL2Dn4qzzg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-menu" "2.0.6" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-roving-focus" "1.0.4" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-popper@1.1.3": + version "1.1.3" + resolved "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz" + integrity sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w== + dependencies: + "@babel/runtime" "^7.13.10" + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-use-rect" "1.0.1" + "@radix-ui/react-use-size" "1.0.1" + "@radix-ui/rect" "1.0.1" + +"@radix-ui/react-portal@1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz" + integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + +"@radix-ui/react-presence@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz" + integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/react-primitive@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz" + integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-slot" "1.0.2" + +"@radix-ui/react-roving-focus@1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz" + integrity sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-slider@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.1.2.tgz" + integrity sha512-NKs15MJylfzVsCagVSWKhGGLNR1W9qWs+HtgbmjjVUB3B9+lb3PYoXxVju3kOrpf0VKyVCtZp+iTwVoqpa1Chw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/number" "1.0.1" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-use-previous" "1.0.1" + "@radix-ui/react-use-size" "1.0.1" + +"@radix-ui/react-slot@^1.0.2", "@radix-ui/react-slot@1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz" + integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + +"@radix-ui/react-use-callback-ref@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz" + integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-controllable-state@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz" + integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-use-escape-keydown@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz" + integrity sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-use-layout-effect@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz" + integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-previous@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.0.1.tgz" + integrity sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-use-rect@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz" + integrity sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/rect" "1.0.1" + +"@radix-ui/react-use-size@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz" + integrity sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/rect@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz" + integrity sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ== + dependencies: + "@babel/runtime" "^7.13.10" + +"@remix-run/router@1.15.2": + version "1.15.2" + resolved "https://registry.npmjs.org/@remix-run/router/-/router-1.15.2.tgz" + integrity sha512-+Rnav+CaoTE5QJc4Jcwh5toUpnVLKYbpU6Ys0zqbakqbaLQHeglLVHPfxOiQqdNmUy5C2lXz5dwC6tQNX2JW2Q== + +"@swc/helpers@0.5.2": + version "0.5.2" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz" + integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw== + dependencies: + tslib "^2.4.0" + +"@types/babel__core@^7.20.4": + version "7.20.4" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.4.tgz" + integrity sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.7" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz" + integrity sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*": + version "7.20.4" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz" + integrity sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA== + dependencies: + "@babel/types" "^7.20.7" + +"@types/d3-array@^3.0.3": + version "3.2.1" + resolved "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz" + integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg== + +"@types/d3-color@*": + version "3.1.3" + resolved "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz" + integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== + +"@types/d3-ease@^3.0.0": + version "3.0.2" + resolved "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz" + integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA== + +"@types/d3-interpolate@^3.0.1": + version "3.0.4" + resolved "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz" + integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== + dependencies: + "@types/d3-color" "*" + +"@types/d3-path@*": + version "3.0.2" + resolved "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.2.tgz" + integrity sha512-WAIEVlOCdd/NKRYTsqCpOMHQHemKBEINf8YXMYOtXH0GA7SY0dqMB78P3Uhgfy+4X+/Mlw2wDtlETkN6kQUCMA== + +"@types/d3-scale@^4.0.2": + version "4.0.8" + resolved "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.8.tgz" + integrity sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ== + dependencies: + "@types/d3-time" "*" + +"@types/d3-shape@^3.1.0": + version "3.1.6" + resolved "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.6.tgz" + integrity sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA== + dependencies: + "@types/d3-path" "*" + +"@types/d3-time@*", "@types/d3-time@^3.0.0": + version "3.0.3" + resolved "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.3.tgz" + integrity sha512-2p6olUZ4w3s+07q3Tm2dbiMZy5pCDfYwtLXXHUnVzXgQlZ/OyPtUz6OL382BkOuGlLXqfT+wqv8Fw2v8/0geBw== + +"@types/d3-timer@^3.0.0": + version "3.0.2" + resolved "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz" + integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== + +"@types/events@^3.0.3": + version "3.0.3" + resolved "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz" + integrity sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g== + +"@types/node@>= 14": + version "20.11.5" + resolved "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz" + integrity sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w== + dependencies: + undici-types "~5.26.4" + +"@types/p5@^0.9.1": + version "0.9.1" + resolved "https://registry.npmjs.org/@types/p5/-/p5-0.9.1.tgz" + integrity sha512-4glOKdqdBiRWDFZwi/MjHudPV2U4t2L4fTTSacGapfFxyNXzZcAshAjqmrJkCIZcFlhRBEAL7AM95xRDMfrIwg== + +"@types/prop-types@*": + version "15.7.10" + resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.10.tgz" + integrity sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A== + +"@types/react-dom@*", "@types/react-dom@^18.2.15": + version "18.2.15" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.15.tgz" + integrity sha512-HWMdW+7r7MR5+PZqJF6YFNSCtjz1T0dsvo/f1BV6HkV+6erD/nA7wd9NM00KVG83zf2nJ7uATPO9ttdIPvi3gg== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^16.8.0 || ^17.0.0 || ^18.0.0", "@types/react@^16.9.0 || ^17.0.0 || ^18.0.0", "@types/react@^18.2.37", "@types/react@>=16.8": + version "18.2.37" + resolved "https://registry.npmjs.org/@types/react/-/react-18.2.37.tgz" + integrity sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + +"@types/scheduler@*": + version "0.16.6" + resolved "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.6.tgz" + integrity sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA== + +"@vitejs/plugin-react@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz" + integrity sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ== + dependencies: + "@babel/core" "^7.23.3" + "@babel/plugin-transform-react-jsx-self" "^7.23.3" + "@babel/plugin-transform-react-jsx-source" "^7.23.3" + "@types/babel__core" "^7.20.4" + react-refresh "^0.14.0" + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^5.0.2: + version "5.0.2" + resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + +aria-hidden@^1.1.1: + version "1.2.3" + resolved "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.3.tgz" + integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== + dependencies: + tslib "^2.0.0" + +attr-accept@^2.2.2: + version "2.2.2" + resolved "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz" + integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== + +autoprefixer@^10.4.16: + version "10.4.16" + resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz" + integrity sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ== + dependencies: + browserslist "^4.21.10" + caniuse-lite "^1.0.30001538" + fraction.js "^4.3.6" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.21.10, browserslist@^4.21.9, "browserslist@>= 4.21.0": + version "4.22.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz" + integrity sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ== + dependencies: + caniuse-lite "^1.0.30001541" + electron-to-chromium "^1.4.535" + node-releases "^2.0.13" + update-browserslist-db "^1.0.13" + +busboy@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + +caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541, caniuse-lite@^1.0.30001579: + version "1.0.30001579" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz" + integrity sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +class-variance-authority@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz" + integrity sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A== + dependencies: + clsx "2.0.0" + +client-only@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + +clsx@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz" + integrity sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg== + +clsx@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz" + integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +commander@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csstype@^3.0.2: + version "3.1.2" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== + +d3-array@^3.1.6, "d3-array@2 - 3", "d3-array@2.10.0 - 3": + version "3.2.4" + resolved "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz" + integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== + dependencies: + internmap "1 - 2" + +"d3-color@1 - 3": + version "3.1.0" + resolved "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +d3-ease@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +"d3-format@1 - 3": + version "3.1.0" + resolved "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== + +d3-interpolate@^3.0.1, "d3-interpolate@1.2.0 - 3": + version "3.0.1" + resolved "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +d3-path@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz" + integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== + +d3-scale@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== + dependencies: + d3-array "2.10.0 - 3" + d3-format "1 - 3" + d3-interpolate "1.2.0 - 3" + d3-time "2.1.1 - 3" + d3-time-format "2 - 4" + +d3-shape@^3.1.0: + version "3.2.0" + resolved "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz" + integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== + dependencies: + d3-path "^3.1.0" + +"d3-time-format@2 - 4": + version "4.1.0" + resolved "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== + dependencies: + d3-time "1 - 3" + +d3-time@^3.0.0, "d3-time@1 - 3", "d3-time@2.1.1 - 3": + version "3.1.0" + resolved "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz" + integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== + dependencies: + d3-array "2 - 3" + +d3-timer@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decimal.js-light@^2.4.1: + version "2.5.1" + resolved "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz" + integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== + +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + +didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +dom-helpers@^3.4.0: + version "3.4.0" + resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz" + integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== + dependencies: + "@babel/runtime" "^7.1.2" + +electron-to-chromium@^1.4.535: + version "1.4.588" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.588.tgz" + integrity sha512-soytjxwbgcCu7nh5Pf4S2/4wa6UIu+A3p03U2yVr53qGxi1/VTR3ENI+p50v+UxqqZAfl48j3z55ud7VHIOr9w== + +esbuild@^0.18.10: + version "0.18.20" + resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +eventemitter3@^4.0.1: + version "4.0.7" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + +events@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +fast-equals@^5.0.0: + version "5.0.1" + resolved "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz" + integrity sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ== + +fast-glob@^3.3.0: + version "3.3.2" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +file-selector@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz" + integrity sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw== + dependencies: + tslib "^2.4.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +fraction.js@^4.3.6: + version "4.3.7" + resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.1.6: + version "7.1.6" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +graceful-fs@^4.2.11: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== + +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +jiti@^1.19.1: + version "1.21.0" + resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz" + integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +lilconfig@^2.0.5, lilconfig@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +lodash@^4.17.19: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lucide-react@^0.292.0: + version "0.292.0" + resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.292.0.tgz" + integrity sha512-rRgUkpEHWpa5VCT66YscInCQmQuPCB1RFRzkkxMxg4b+jaL0V12E3riWWR2Sh5OIiUhCwGW/ZExuEO4Az32E6Q== + +lzma-js-simple-v2@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/lzma-js-simple-v2/-/lzma-js-simple-v2-1.2.2.tgz" + integrity sha512-dHjXHlgcS8r2K+4t8kAycGE4xMVQxPzMTCrrYhaFEtQDmjXh/A7xq4D88oOfEtjTR9XFzTAML9AuBrm4jXLigA== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4, micromatch@^4.0.5: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nanoid@^3.3.6: + version "3.3.7" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +next-themes@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz" + integrity sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A== + +next@*: + version "14.1.0" + resolved "https://registry.npmjs.org/next/-/next-14.1.0.tgz" + integrity sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q== + dependencies: + "@next/env" "14.1.0" + "@swc/helpers" "0.5.2" + busboy "1.6.0" + caniuse-lite "^1.0.30001579" + graceful-fs "^4.2.11" + postcss "8.4.31" + styled-jsx "5.1.1" + optionalDependencies: + "@next/swc-darwin-arm64" "14.1.0" + "@next/swc-darwin-x64" "14.1.0" + "@next/swc-linux-arm64-gnu" "14.1.0" + "@next/swc-linux-arm64-musl" "14.1.0" + "@next/swc-linux-x64-gnu" "14.1.0" + "@next/swc-linux-x64-musl" "14.1.0" + "@next/swc-win32-arm64-msvc" "14.1.0" + "@next/swc-win32-ia32-msvc" "14.1.0" + "@next/swc-win32-x64-msvc" "14.1.0" + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + +object-assign@^4.0.1, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-hash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz" + integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +osu-classes@^3.0.0, osu-classes@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/osu-classes/-/osu-classes-3.0.1.tgz" + integrity sha512-EI0pMoyUAgrvGHeOywaglHaGpjxhCHtwxPsK7kKJMDGmSgT8lvD3Ebs7vkSNPcKAuBX0VMbfsnSrwE9ArkOXyw== + +osu-parsers@^4.1.6: + version "4.1.6" + resolved "https://registry.npmjs.org/osu-parsers/-/osu-parsers-4.1.6.tgz" + integrity sha512-k0PQaWBEZEMiweminI/A4j0lLTvsbHvhU/McMI94yJy+ME1ZfggAOp3vVee1P0Ze0Nu+pT/Ir7b0AlrhJO9IsQ== + dependencies: + lzma-js-simple-v2 "^1.2.2" + +osu-standard-stable@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/osu-standard-stable/-/osu-standard-stable-5.0.0.tgz" + integrity sha512-qCzS1DFStHjgeDZguLRY5k4OgJSNXHG+sUdi1jm2Xwgk23QsyexwRQyTs5phFMuAnQmxeyjzWELLHOo99A/gMA== + +p5@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/p5/-/p5-1.3.1.tgz" + integrity sha512-g7W2htgEwiAEGcl0WHccAJKbunUJwrUojUSR9+KihphJ33p5VpDdh1K8pDx4ppYjOr/lVEXaZ1XXDj27nwlNOg== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pirates@^4.0.1: + version "4.0.6" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +postcss-import@^15.1.0: + version "15.1.0" + resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz" + integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-js@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz" + integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== + dependencies: + camelcase-css "^2.0.1" + +postcss-load-config@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz" + integrity sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA== + dependencies: + lilconfig "^2.0.5" + yaml "^2.1.1" + +postcss-nested@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz" + integrity sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ== + dependencies: + postcss-selector-parser "^6.0.11" + +postcss-selector-parser@^6.0.11: + version "6.0.13" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz" + integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.0.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.0.0, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.27, postcss@^8.4.31, postcss@>=8.0.9, postcss@8.4.31: + version "8.4.31" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-dom@*, "react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8 || ^17.0 || ^18.0", react-dom@^18.0.0, react-dom@^18.2.0, react-dom@>=15.0.0, react-dom@>=16.8, react-dom@>=16.8.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" + integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== + dependencies: + loose-envify "^1.1.0" + scheduler "^0.23.0" + +react-dropzone@^14.2.3: + version "14.2.3" + resolved "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.3.tgz" + integrity sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug== + dependencies: + attr-accept "^2.2.2" + file-selector "^0.6.0" + prop-types "^15.8.1" + +react-is@^16.10.2, react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-refresh@^0.14.0: + version "0.14.0" + resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz" + integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== + +react-remove-scroll-bar@^2.3.3: + version "2.3.4" + resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz" + integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A== + dependencies: + react-style-singleton "^2.2.1" + tslib "^2.0.0" + +react-remove-scroll@2.5.5: + version "2.5.5" + resolved "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz" + integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw== + dependencies: + react-remove-scroll-bar "^2.3.3" + react-style-singleton "^2.2.1" + tslib "^2.1.0" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" + +react-router-dom@^6.22.2: + version "6.22.2" + resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.2.tgz" + integrity sha512-WgqxD2qySEIBPZ3w0sHH+PUAiamDeszls9tzqMPBDA1YYVucTBXLU7+gtRfcSnhe92A3glPnvSxK2dhNoAVOIQ== + dependencies: + "@remix-run/router" "1.15.2" + react-router "6.22.2" + +react-router@6.22.2: + version "6.22.2" + resolved "https://registry.npmjs.org/react-router/-/react-router-6.22.2.tgz" + integrity sha512-YD3Dzprzpcq+tBMHBS822tCjnWD3iIZbTeSXMY9LPSG541EfoBGyZ3bS25KEnaZjLcmQpw2AVLkFyfgXY8uvcw== + dependencies: + "@remix-run/router" "1.15.2" + +react-smooth@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.5.tgz" + integrity sha512-BMP2Ad42tD60h0JW6BFaib+RJuV5dsXJK9Baxiv/HlNFjvRLqA9xrNKxVWnUIZPQfzUwGXIlU/dSYLU+54YGQA== + dependencies: + fast-equals "^5.0.0" + react-transition-group "2.9.0" + +react-style-singleton@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz" + integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^2.0.0" + +react-transition-group@2.9.0: + version "2.9.0" + resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz" + integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg== + dependencies: + dom-helpers "^3.4.0" + loose-envify "^1.4.0" + prop-types "^15.6.2" + react-lifecycles-compat "^3.0.4" + +react@*, "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.5.1 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", react@^18.0.0, react@^18.2.0, "react@>= 16.8 || 18.0.0", "react@>= 16.8.0 || 17.x.x || ^18.0.0-0", react@>=15.0.0, react@>=16.8, react@>=16.8.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" + integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== + dependencies: + loose-envify "^1.1.0" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz" + integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA== + dependencies: + pify "^2.3.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +recharts-scale@^0.4.4: + version "0.4.5" + resolved "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz" + integrity sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w== + dependencies: + decimal.js-light "^2.4.1" + +recharts@^2.10.4: + version "2.10.4" + resolved "https://registry.npmjs.org/recharts/-/recharts-2.10.4.tgz" + integrity sha512-/Q7/wdf8bW91lN3NEeCjL9RWfaiXQViJFgdnas4Eix/I8B9HAI3tHHK/CW/zDfgRMh4fzW1zlfjoz1IAapLO1Q== + dependencies: + clsx "^2.0.0" + eventemitter3 "^4.0.1" + lodash "^4.17.19" + react-is "^16.10.2" + react-smooth "^2.0.5" + recharts-scale "^0.4.4" + tiny-invariant "^1.3.1" + victory-vendor "^36.6.8" + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +resolve@^1.1.7, resolve@^1.22.2: + version "1.22.8" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rollup@^3.27.1: + version "3.29.4" + resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz" + integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== + optionalDependencies: + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +scheduler@^0.23.0: + version "0.23.0" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz" + integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== + dependencies: + loose-envify "^1.1.0" + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +sonner@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/sonner/-/sonner-1.3.1.tgz" + integrity sha512-+rOAO56b2eI3q5BtgljERSn2umRk63KFIvgb2ohbZ5X+Eb5u+a/7/0ZgswYqgBMg8dyl7n6OXd9KasA8QF9ToA== + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +styled-jsx@5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz" + integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw== + dependencies: + client-only "0.0.1" + +sucrase@^3.32.0: + version "3.34.0" + resolved "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz" + integrity sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "7.1.6" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tailwind-merge@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.0.tgz" + integrity sha512-SqqhhaL0T06SW59+JVNfAqKdqLs0497esifRrZ7jOaefP3o64fdFNDMrAQWZFMxTLJPiHVjRLUywT8uFz1xNWQ== + dependencies: + "@babel/runtime" "^7.23.5" + +tailwindcss-animate@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz" + integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA== + +tailwindcss@^3.3.5, "tailwindcss@>=3.0.0 || insiders": + version "3.3.5" + resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz" + integrity sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.3.0" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.19.1" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +tiny-invariant@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz" + integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + +ts-md5@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz" + integrity sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg== + +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0: + version "2.6.2" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +typescript@^4.2.3: + version "4.2.4" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz" + integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +use-callback-ref@^1.3.0: + version "1.3.1" + resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.1.tgz" + integrity sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ== + dependencies: + tslib "^2.0.0" + +use-sidecar@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz" + integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + +use-sync-external-store@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utility-types@^3.10.0: + version "3.11.0" + resolved "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz" + integrity sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw== + +victory-vendor@^36.6.8: + version "36.8.2" + resolved "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.8.2.tgz" + integrity sha512-NfSQi7ISCdBbDpn3b6rg+8RpFZmWIM9mcks48BbogHE2F6h1XKdA34oiCKP5hP1OGvTotDRzsexiJKzrK4Exuw== + dependencies: + "@types/d3-array" "^3.0.3" + "@types/d3-ease" "^3.0.0" + "@types/d3-interpolate" "^3.0.1" + "@types/d3-scale" "^4.0.2" + "@types/d3-shape" "^3.1.0" + "@types/d3-time" "^3.0.0" + "@types/d3-timer" "^3.0.0" + d3-array "^3.1.6" + d3-ease "^3.0.1" + d3-interpolate "^3.0.1" + d3-scale "^4.0.2" + d3-shape "^3.1.0" + d3-time "^3.0.0" + d3-timer "^3.0.1" + +"vite@^4.2.0 || ^5.0.0", vite@^4.4.5: + version "4.5.2" + resolved "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz" + integrity sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w== + dependencies: + esbuild "^0.18.10" + postcss "^8.4.27" + rollup "^3.27.1" + optionalDependencies: + fsevents "~2.3.2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^2.1.1: + version "2.3.4" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz" + integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== + +zustand@^4.4.1: + version "4.4.1" + resolved "https://registry.npmjs.org/zustand/-/zustand-4.4.1.tgz" + integrity sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw== + dependencies: + use-sync-external-store "1.2.0"