]> git.localhorst.tv Git - alttp.git/commitdiff
add known bot master
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 2 Jul 2025 17:25:10 +0000 (19:25 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 2 Jul 2025 17:25:10 +0000 (19:25 +0200)
468 files changed:
.editorconfig
.env.example
.gitignore
.gitmodules
app/Console/Commands/ChatlibDatabase.php
app/Console/Commands/ChatlibGenerate.php
app/Console/Commands/DiscordBotCommand.php
app/Console/Commands/ReevaluateChatCommand.php
app/Console/Commands/SyncCabookey.php [new file with mode: 0644]
app/Console/Commands/SyncLadder.php
app/Console/Commands/SyncRacetime.php
app/Console/Commands/SyncSpeedGaming.php
app/Console/Commands/SyncStepLadder.php [new file with mode: 0644]
app/Console/Commands/SyncStepLadderFull.php [new file with mode: 0644]
app/Console/Commands/SyncZSR.php
app/Console/Commands/TwitchAuth.php
app/Console/Commands/TwitchChannelClips.php [new file with mode: 0644]
app/Console/Commands/TwitchChannelInfo.php
app/Console/Commands/UnlockRound.php [new file with mode: 0644]
app/Console/Kernel.php
app/DiscordBotCommands/BaseCommand.php
app/DiscordBotCommands/MessageCommand.php [new file with mode: 0644]
app/Events/RoundChanged.php
app/Http/Controllers/ChannelController.php
app/Http/Controllers/ChatBotLogController.php [new file with mode: 0644]
app/Http/Controllers/DiscordBotController.php [new file with mode: 0644]
app/Http/Controllers/DiscordController.php [deleted file]
app/Http/Controllers/EpisodeController.php
app/Http/Controllers/ProtocolController.php
app/Http/Controllers/ResultController.php
app/Http/Controllers/RoundController.php
app/Http/Controllers/SitemapXmlController.php
app/Http/Controllers/TournamentController.php
app/Http/Controllers/UserController.php
app/Models/Channel.php
app/Models/ChatBotLog.php
app/Models/ChatLib.php
app/Models/ChatLog.php
app/Models/DiscordBotCommand.php
app/Models/DiscordGuild.php
app/Models/Protocol.php
app/Models/Result.php
app/Models/Round.php
app/Models/StepLadderMode.php [new file with mode: 0644]
app/Models/Tournament.php
app/Models/User.php
app/Policies/DiscordGuildPolicy.php
app/Policies/RoundPolicy.php
app/TwitchBot/IRCMessage.php
app/TwitchBot/TokenizedMessage.php
app/TwitchBot/TwitchBot.php
app/TwitchBot/TwitchChatBot.php
ci.sh
composer.json
composer.lock
config/broadcasting.php
config/larascord.php
config/reverb.php [new file with mode: 0644]
database/migrations/2023_05_25_121158_add_remember_token_to_users_table.php [new file with mode: 0644]
database/migrations/2023_05_26_165816_create_discord_access_tokens_table.php [new file with mode: 0644]
database/migrations/2023_05_27_055058_remove_refresh_token_from_users_table.php [new file with mode: 0644]
database/migrations/2023_06_11_062809_update_users_table.php [new file with mode: 0644]
database/migrations/2024_07_13_124353_chat_logs_emote_only.php [new file with mode: 0644]
database/migrations/2024_09_06_090755_more_twitch_props.php [new file with mode: 0644]
database/migrations/2025_05_07_123722_add_tournament_result_reveal_column.php [new file with mode: 0644]
database/migrations/2025_05_19_162331_create_step_ladder_modes_table.php [new file with mode: 0644]
database/migrations/2025_05_21_104956_tournament_description.php [new file with mode: 0644]
database/migrations/2025_07_02_095525_link_discord_bot_commands_and_guilds.php [new file with mode: 0644]
eslint.config.mjs [new file with mode: 0644]
package-lock.json
package.json
phpunit.xml
public/dunkatracker
public/muffins-smz3 [new submodule]
public/muffinstracker
resources/js/app/Footer.js [deleted file]
resources/js/app/Footer.jsx [new file with mode: 0644]
resources/js/app/FullLayout.js [deleted file]
resources/js/app/FullLayout.jsx [new file with mode: 0644]
resources/js/app/Header.js [deleted file]
resources/js/app/Header.jsx [new file with mode: 0644]
resources/js/app/LanguageSwitcher.js [deleted file]
resources/js/app/LanguageSwitcher.jsx [new file with mode: 0644]
resources/js/app/PrivacyDialog.js [deleted file]
resources/js/app/PrivacyDialog.jsx [new file with mode: 0644]
resources/js/app/Routes.js [deleted file]
resources/js/app/Routes.jsx [new file with mode: 0644]
resources/js/app/User.js [deleted file]
resources/js/app/User.jsx [new file with mode: 0644]
resources/js/app/index.js [deleted file]
resources/js/app/index.jsx [new file with mode: 0644]
resources/js/bootstrap.js
resources/js/components/alttp-seeds/BaseRomButton.js [deleted file]
resources/js/components/alttp-seeds/BaseRomButton.jsx [new file with mode: 0644]
resources/js/components/alttp-seeds/Seed.js [deleted file]
resources/js/components/alttp-seeds/Seed.jsx [new file with mode: 0644]
resources/js/components/applications/Button.js [deleted file]
resources/js/components/applications/Button.jsx [new file with mode: 0644]
resources/js/components/applications/Dialog.js [deleted file]
resources/js/components/applications/Dialog.jsx [new file with mode: 0644]
resources/js/components/applications/Item.js [deleted file]
resources/js/components/applications/Item.jsx [new file with mode: 0644]
resources/js/components/applications/List.js [deleted file]
resources/js/components/applications/List.jsx [new file with mode: 0644]
resources/js/components/channel/Item.jsx [new file with mode: 0644]
resources/js/components/channel/Link.jsx [new file with mode: 0644]
resources/js/components/channel/List.jsx [new file with mode: 0644]
resources/js/components/chat-bot-logs/ChatBotLog.js [deleted file]
resources/js/components/chat-bot-logs/ChatBotLog.jsx [new file with mode: 0644]
resources/js/components/chat-bot-logs/Dialog.js [deleted file]
resources/js/components/chat-bot-logs/Dialog.jsx [new file with mode: 0644]
resources/js/components/chat-bot-logs/Item.js [deleted file]
resources/js/components/chat-bot-logs/Item.jsx [new file with mode: 0644]
resources/js/components/chat-bot-logs/List.js [deleted file]
resources/js/components/chat-bot-logs/List.jsx [new file with mode: 0644]
resources/js/components/chat-logs/Item.jsx [new file with mode: 0644]
resources/js/components/chat-logs/List.jsx [new file with mode: 0644]
resources/js/components/common/AspectBox.js [deleted file]
resources/js/components/common/AspectBox.jsx [new file with mode: 0644]
resources/js/components/common/CanonicalLinks.js [deleted file]
resources/js/components/common/CanonicalLinks.jsx [new file with mode: 0644]
resources/js/components/common/ChannelSelect.js [deleted file]
resources/js/components/common/ChannelSelect.jsx [new file with mode: 0644]
resources/js/components/common/DiscordChannelSelect.js [deleted file]
resources/js/components/common/DiscordChannelSelect.jsx [new file with mode: 0644]
resources/js/components/common/DiscordSelect.js [deleted file]
resources/js/components/common/DiscordSelect.jsx [new file with mode: 0644]
resources/js/components/common/ErrorBoundary.js [deleted file]
resources/js/components/common/ErrorBoundary.jsx [new file with mode: 0644]
resources/js/components/common/ErrorMessage.js [deleted file]
resources/js/components/common/ErrorMessage.jsx [new file with mode: 0644]
resources/js/components/common/HTMLInput.js [deleted file]
resources/js/components/common/HTMLInput.jsx [new file with mode: 0644]
resources/js/components/common/Icon.js [deleted file]
resources/js/components/common/Icon.jsx [new file with mode: 0644]
resources/js/components/common/LargeCheck.js [deleted file]
resources/js/components/common/LargeCheck.jsx [new file with mode: 0644]
resources/js/components/common/Loading.js [deleted file]
resources/js/components/common/Loading.jsx [new file with mode: 0644]
resources/js/components/common/PngDialog.js [deleted file]
resources/js/components/common/PngDialog.jsx [new file with mode: 0644]
resources/js/components/common/PngPlayer.js [deleted file]
resources/js/components/common/PngPlayer.jsx [new file with mode: 0644]
resources/js/components/common/RawHTML.js [deleted file]
resources/js/components/common/RawHTML.jsx [new file with mode: 0644]
resources/js/components/common/Slider.js [deleted file]
resources/js/components/common/Slider.jsx [new file with mode: 0644]
resources/js/components/common/Spoiler.js [deleted file]
resources/js/components/common/Spoiler.jsx [new file with mode: 0644]
resources/js/components/common/ToggleSwitch.js [deleted file]
resources/js/components/common/ToggleSwitch.jsx [new file with mode: 0644]
resources/js/components/common/UserSelect.js [deleted file]
resources/js/components/common/UserSelect.jsx [new file with mode: 0644]
resources/js/components/common/ZeldaIcon.js [deleted file]
resources/js/components/common/ZeldaIcon.jsx [new file with mode: 0644]
resources/js/components/discord-bot/ChannelControls.jsx [new file with mode: 0644]
resources/js/components/discord-bot/Controls.js [deleted file]
resources/js/components/discord-bot/Controls.jsx [new file with mode: 0644]
resources/js/components/discord-guilds/Box.js [deleted file]
resources/js/components/discord-guilds/Box.jsx [new file with mode: 0644]
resources/js/components/discord-guilds/ChannelBox.js [deleted file]
resources/js/components/discord-guilds/ChannelBox.jsx [new file with mode: 0644]
resources/js/components/episodes/ApplyDialog.js [deleted file]
resources/js/components/episodes/ApplyDialog.jsx [new file with mode: 0644]
resources/js/components/episodes/ApplyForm.js [deleted file]
resources/js/components/episodes/ApplyForm.jsx [new file with mode: 0644]
resources/js/components/episodes/Channel.js [deleted file]
resources/js/components/episodes/Channel.jsx [new file with mode: 0644]
resources/js/components/episodes/Channels.js [deleted file]
resources/js/components/episodes/Channels.jsx [new file with mode: 0644]
resources/js/components/episodes/Crew.js [deleted file]
resources/js/components/episodes/Crew.jsx [new file with mode: 0644]
resources/js/components/episodes/CrewManagement.js [deleted file]
resources/js/components/episodes/CrewManagement.jsx [new file with mode: 0644]
resources/js/components/episodes/CrewMember.js [deleted file]
resources/js/components/episodes/CrewMember.jsx [new file with mode: 0644]
resources/js/components/episodes/DialogEpisode.js [deleted file]
resources/js/components/episodes/DialogEpisode.jsx [new file with mode: 0644]
resources/js/components/episodes/Filter.js [deleted file]
resources/js/components/episodes/Filter.jsx [new file with mode: 0644]
resources/js/components/episodes/Item.js [deleted file]
resources/js/components/episodes/Item.jsx [new file with mode: 0644]
resources/js/components/episodes/List.js [deleted file]
resources/js/components/episodes/List.jsx [new file with mode: 0644]
resources/js/components/episodes/MultiLink.js [deleted file]
resources/js/components/episodes/MultiLink.jsx [new file with mode: 0644]
resources/js/components/episodes/Player.js [deleted file]
resources/js/components/episodes/Player.jsx [new file with mode: 0644]
resources/js/components/episodes/Players.js [deleted file]
resources/js/components/episodes/Players.jsx [new file with mode: 0644]
resources/js/components/episodes/RestreamAddForm.js [deleted file]
resources/js/components/episodes/RestreamAddForm.jsx [new file with mode: 0644]
resources/js/components/episodes/RestreamDialog.js [deleted file]
resources/js/components/episodes/RestreamDialog.jsx [new file with mode: 0644]
resources/js/components/episodes/RestreamEditForm.js [deleted file]
resources/js/components/episodes/RestreamEditForm.jsx [new file with mode: 0644]
resources/js/components/events/Detail.js [deleted file]
resources/js/components/events/Detail.jsx [new file with mode: 0644]
resources/js/components/events/Item.js [deleted file]
resources/js/components/events/Item.jsx [new file with mode: 0644]
resources/js/components/events/List.js [deleted file]
resources/js/components/events/List.jsx [new file with mode: 0644]
resources/js/components/map/Buttons.js [deleted file]
resources/js/components/map/Buttons.jsx [new file with mode: 0644]
resources/js/components/map/Item.js [deleted file]
resources/js/components/map/Item.jsx [new file with mode: 0644]
resources/js/components/map/List.js [deleted file]
resources/js/components/map/List.jsx [new file with mode: 0644]
resources/js/components/map/OpenSeadragon.js [deleted file]
resources/js/components/map/OpenSeadragon.jsx [new file with mode: 0644]
resources/js/components/map/Overlay.js [deleted file]
resources/js/components/map/Overlay.jsx [new file with mode: 0644]
resources/js/components/map/Pin.js [deleted file]
resources/js/components/map/Pin.jsx [new file with mode: 0644]
resources/js/components/map/Pins.js [deleted file]
resources/js/components/map/Pins.jsx [new file with mode: 0644]
resources/js/components/map/Popover.js [deleted file]
resources/js/components/map/Popover.jsx [new file with mode: 0644]
resources/js/components/map/UWSuperTiles.js [deleted file]
resources/js/components/map/UWSuperTiles.jsx [new file with mode: 0644]
resources/js/components/map/Viewer.js [deleted file]
resources/js/components/map/Viewer.jsx [new file with mode: 0644]
resources/js/components/participants/List.js [deleted file]
resources/js/components/participants/List.jsx [new file with mode: 0644]
resources/js/components/protocol/Dialog.js [deleted file]
resources/js/components/protocol/Dialog.jsx [new file with mode: 0644]
resources/js/components/protocol/Item.js [deleted file]
resources/js/components/protocol/Item.jsx [new file with mode: 0644]
resources/js/components/protocol/List.js [deleted file]
resources/js/components/protocol/List.jsx [new file with mode: 0644]
resources/js/components/protocol/Protocol.js [deleted file]
resources/js/components/protocol/Protocol.jsx [new file with mode: 0644]
resources/js/components/protocol/RoundProtocol.jsx [new file with mode: 0644]
resources/js/components/results/DetailDialog.js [deleted file]
resources/js/components/results/DetailDialog.jsx [new file with mode: 0644]
resources/js/components/results/Item.js [deleted file]
resources/js/components/results/Item.jsx [new file with mode: 0644]
resources/js/components/results/List.js [deleted file]
resources/js/components/results/List.jsx [new file with mode: 0644]
resources/js/components/results/ReportButton.js [deleted file]
resources/js/components/results/ReportButton.jsx [new file with mode: 0644]
resources/js/components/results/ReportDialog.js [deleted file]
resources/js/components/results/ReportDialog.jsx [new file with mode: 0644]
resources/js/components/results/ReportForm.js [deleted file]
resources/js/components/results/ReportForm.jsx [new file with mode: 0644]
resources/js/components/rounds/DeleteButton.jsx [new file with mode: 0644]
resources/js/components/rounds/DeleteDialog.jsx [new file with mode: 0644]
resources/js/components/rounds/EditButton.js [deleted file]
resources/js/components/rounds/EditButton.jsx [new file with mode: 0644]
resources/js/components/rounds/EditDialog.js [deleted file]
resources/js/components/rounds/EditDialog.jsx [new file with mode: 0644]
resources/js/components/rounds/EditForm.js [deleted file]
resources/js/components/rounds/EditForm.jsx [new file with mode: 0644]
resources/js/components/rounds/Item.js [deleted file]
resources/js/components/rounds/Item.jsx [new file with mode: 0644]
resources/js/components/rounds/List.js [deleted file]
resources/js/components/rounds/List.jsx [new file with mode: 0644]
resources/js/components/rounds/LoadMore.js [deleted file]
resources/js/components/rounds/LoadMore.jsx [new file with mode: 0644]
resources/js/components/rounds/LockButton.js [deleted file]
resources/js/components/rounds/LockButton.jsx [new file with mode: 0644]
resources/js/components/rounds/LockDialog.js [deleted file]
resources/js/components/rounds/LockDialog.jsx [new file with mode: 0644]
resources/js/components/rounds/SeedButton.js [deleted file]
resources/js/components/rounds/SeedButton.jsx [new file with mode: 0644]
resources/js/components/rounds/SeedCode.js [deleted file]
resources/js/components/rounds/SeedCode.jsx [new file with mode: 0644]
resources/js/components/rounds/SeedCodeInput.js [deleted file]
resources/js/components/rounds/SeedCodeInput.jsx [new file with mode: 0644]
resources/js/components/rounds/SeedDialog.js [deleted file]
resources/js/components/rounds/SeedDialog.jsx [new file with mode: 0644]
resources/js/components/rounds/SeedForm.js [deleted file]
resources/js/components/rounds/SeedForm.jsx [new file with mode: 0644]
resources/js/components/rounds/SeedRolledBy.js [deleted file]
resources/js/components/rounds/SeedRolledBy.jsx [new file with mode: 0644]
resources/js/components/snes/SettingsDialog.js [deleted file]
resources/js/components/snes/SettingsDialog.jsx [new file with mode: 0644]
resources/js/components/snes/SettingsForm.js [deleted file]
resources/js/components/snes/SettingsForm.jsx [new file with mode: 0644]
resources/js/components/techniques/Detail.js [deleted file]
resources/js/components/techniques/Detail.jsx [new file with mode: 0644]
resources/js/components/techniques/Dialog.js [deleted file]
resources/js/components/techniques/Dialog.jsx [new file with mode: 0644]
resources/js/components/techniques/Form.js [deleted file]
resources/js/components/techniques/Form.jsx [new file with mode: 0644]
resources/js/components/techniques/List.js [deleted file]
resources/js/components/techniques/List.jsx [new file with mode: 0644]
resources/js/components/techniques/Outline.js [deleted file]
resources/js/components/techniques/Outline.jsx [new file with mode: 0644]
resources/js/components/techniques/Overview.js [deleted file]
resources/js/components/techniques/Overview.jsx [new file with mode: 0644]
resources/js/components/techniques/Requirement.js [deleted file]
resources/js/components/techniques/Requirement.jsx [new file with mode: 0644]
resources/js/components/techniques/Requirements.js [deleted file]
resources/js/components/techniques/Requirements.jsx [new file with mode: 0644]
resources/js/components/techniques/Rulesets.js [deleted file]
resources/js/components/techniques/Rulesets.jsx [new file with mode: 0644]
resources/js/components/techniques/TechFilter.js [deleted file]
resources/js/components/techniques/TechFilter.jsx [new file with mode: 0644]
resources/js/components/tournament/ApplyButton.js [deleted file]
resources/js/components/tournament/ApplyButton.jsx [new file with mode: 0644]
resources/js/components/tournament/Detail.js [deleted file]
resources/js/components/tournament/Detail.jsx [new file with mode: 0644]
resources/js/components/tournament/DiscordForm.js [deleted file]
resources/js/components/tournament/DiscordForm.jsx [new file with mode: 0644]
resources/js/components/tournament/ScoreChart.js [deleted file]
resources/js/components/tournament/ScoreChart.jsx [new file with mode: 0644]
resources/js/components/tournament/ScoreChartButton.js [deleted file]
resources/js/components/tournament/ScoreChartButton.jsx [new file with mode: 0644]
resources/js/components/tournament/ScoreChartDialog.js [deleted file]
resources/js/components/tournament/ScoreChartDialog.jsx [new file with mode: 0644]
resources/js/components/tournament/Scoreboard.js [deleted file]
resources/js/components/tournament/Scoreboard.jsx [new file with mode: 0644]
resources/js/components/tournament/SettingsButton.js [deleted file]
resources/js/components/tournament/SettingsButton.jsx [new file with mode: 0644]
resources/js/components/tournament/SettingsDialog.js [deleted file]
resources/js/components/tournament/SettingsDialog.jsx [new file with mode: 0644]
resources/js/components/tracker/AutoTracking.js [deleted file]
resources/js/components/tracker/AutoTracking.jsx [new file with mode: 0644]
resources/js/components/tracker/Canvas.js [deleted file]
resources/js/components/tracker/Canvas.jsx [new file with mode: 0644]
resources/js/components/tracker/ConfigDialog.js [deleted file]
resources/js/components/tracker/ConfigDialog.jsx [new file with mode: 0644]
resources/js/components/tracker/CountDisplay.js [deleted file]
resources/js/components/tracker/CountDisplay.jsx [new file with mode: 0644]
resources/js/components/tracker/Dungeons.js [deleted file]
resources/js/components/tracker/Dungeons.jsx [new file with mode: 0644]
resources/js/components/tracker/Equipment.js [deleted file]
resources/js/components/tracker/Equipment.jsx [new file with mode: 0644]
resources/js/components/tracker/Items.js [deleted file]
resources/js/components/tracker/Items.jsx [new file with mode: 0644]
resources/js/components/tracker/Map/Overworld.js [deleted file]
resources/js/components/tracker/Map/Overworld.jsx [new file with mode: 0644]
resources/js/components/tracker/Map/index.js [deleted file]
resources/js/components/tracker/Map/index.jsx [new file with mode: 0644]
resources/js/components/tracker/ToggleIcon.js [deleted file]
resources/js/components/tracker/ToggleIcon.jsx [new file with mode: 0644]
resources/js/components/tracker/Toolbar.js [deleted file]
resources/js/components/tracker/Toolbar.jsx [new file with mode: 0644]
resources/js/components/tracker/index.js [deleted file]
resources/js/components/tracker/index.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/ChatSettingsForm.js [deleted file]
resources/js/components/twitch-bot/ChatSettingsForm.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/Command.js [deleted file]
resources/js/components/twitch-bot/Command.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/CommandDialog.js [deleted file]
resources/js/components/twitch-bot/CommandDialog.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/CommandForm.js [deleted file]
resources/js/components/twitch-bot/CommandForm.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/Commands.js [deleted file]
resources/js/components/twitch-bot/Commands.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/Controls.js [deleted file]
resources/js/components/twitch-bot/Controls.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/GuessingGameAutoTracking.js [deleted file]
resources/js/components/twitch-bot/GuessingGameAutoTracking.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/GuessingGameControls.js [deleted file]
resources/js/components/twitch-bot/GuessingGameControls.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/GuessingGuess.js [deleted file]
resources/js/components/twitch-bot/GuessingGuess.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/GuessingSettingsForm.js [deleted file]
resources/js/components/twitch-bot/GuessingSettingsForm.jsx [new file with mode: 0644]
resources/js/components/twitch-bot/GuessingWinner.js [deleted file]
resources/js/components/twitch-bot/GuessingWinner.jsx [new file with mode: 0644]
resources/js/components/users/Box.js [deleted file]
resources/js/components/users/Box.jsx [new file with mode: 0644]
resources/js/components/users/EditNicknameButton.js [deleted file]
resources/js/components/users/EditNicknameButton.jsx [new file with mode: 0644]
resources/js/components/users/EditNicknameDialog.js [deleted file]
resources/js/components/users/EditNicknameDialog.jsx [new file with mode: 0644]
resources/js/components/users/EditNicknameForm.js [deleted file]
resources/js/components/users/EditNicknameForm.jsx [new file with mode: 0644]
resources/js/components/users/EditStreamLinkButton.js [deleted file]
resources/js/components/users/EditStreamLinkButton.jsx [new file with mode: 0644]
resources/js/components/users/EditStreamLinkDialog.js [deleted file]
resources/js/components/users/EditStreamLinkDialog.jsx [new file with mode: 0644]
resources/js/components/users/EditStreamLinkForm.js [deleted file]
resources/js/components/users/EditStreamLinkForm.jsx [new file with mode: 0644]
resources/js/components/users/Participation.js [deleted file]
resources/js/components/users/Participation.jsx [new file with mode: 0644]
resources/js/components/users/Profile.js [deleted file]
resources/js/components/users/Profile.jsx [new file with mode: 0644]
resources/js/components/users/Records.js [deleted file]
resources/js/components/users/Records.jsx [new file with mode: 0644]
resources/js/components/zootr/MixedPoolsTracker.jsx [new file with mode: 0644]
resources/js/helpers/AlttpBaseRomContext.js [deleted file]
resources/js/helpers/AlttpBaseRomContext.jsx [new file with mode: 0644]
resources/js/helpers/Channel.js
resources/js/helpers/Episode.js
resources/js/helpers/Event.js
resources/js/helpers/Result.js [deleted file]
resources/js/helpers/Result.jsx [new file with mode: 0644]
resources/js/helpers/Round.js
resources/js/helpers/nl2br.js [deleted file]
resources/js/helpers/nl2br.jsx [new file with mode: 0644]
resources/js/helpers/permissions.js
resources/js/hooks/snes.js [deleted file]
resources/js/hooks/snes.jsx [new file with mode: 0644]
resources/js/hooks/tracker.js [deleted file]
resources/js/hooks/tracker.jsx [new file with mode: 0644]
resources/js/hooks/user.js [deleted file]
resources/js/hooks/user.jsx [new file with mode: 0644]
resources/js/i18n/de.js
resources/js/i18n/en.js
resources/js/i18n/index.js
resources/js/index.js [deleted file]
resources/js/index.jsx [new file with mode: 0644]
resources/js/pages/AlttpSeed.js [deleted file]
resources/js/pages/AlttpSeed.jsx [new file with mode: 0644]
resources/js/pages/DiscordBot.js [deleted file]
resources/js/pages/DiscordBot.jsx [new file with mode: 0644]
resources/js/pages/DoorsTracker.js [deleted file]
resources/js/pages/DoorsTracker.jsx [new file with mode: 0644]
resources/js/pages/Event.js [deleted file]
resources/js/pages/Event.jsx [new file with mode: 0644]
resources/js/pages/Events.js [deleted file]
resources/js/pages/Events.jsx [new file with mode: 0644]
resources/js/pages/Front.js [deleted file]
resources/js/pages/Front.jsx [new file with mode: 0644]
resources/js/pages/GuessingGameControls.js [deleted file]
resources/js/pages/GuessingGameControls.jsx [new file with mode: 0644]
resources/js/pages/GuessingGameMonitor.js [deleted file]
resources/js/pages/GuessingGameMonitor.jsx [new file with mode: 0644]
resources/js/pages/HorstieLog.jsx [new file with mode: 0644]
resources/js/pages/Map.js [deleted file]
resources/js/pages/Map.jsx [new file with mode: 0644]
resources/js/pages/NotFound.js [deleted file]
resources/js/pages/NotFound.jsx [new file with mode: 0644]
resources/js/pages/Schedule.js [deleted file]
resources/js/pages/Schedule.jsx [new file with mode: 0644]
resources/js/pages/Technique.js [deleted file]
resources/js/pages/Technique.jsx [new file with mode: 0644]
resources/js/pages/Techniques.js [deleted file]
resources/js/pages/Techniques.jsx [new file with mode: 0644]
resources/js/pages/Tournament.js [deleted file]
resources/js/pages/Tournament.jsx [new file with mode: 0644]
resources/js/pages/Tracker.js [deleted file]
resources/js/pages/Tracker.jsx [new file with mode: 0644]
resources/js/pages/TwitchBot.js [deleted file]
resources/js/pages/TwitchBot.jsx [new file with mode: 0644]
resources/js/pages/TwitchLegal.js [deleted file]
resources/js/pages/TwitchLegal.jsx [new file with mode: 0644]
resources/js/pages/User.js [deleted file]
resources/js/pages/User.jsx [new file with mode: 0644]
resources/js/pages/ZootrMixedPoolsTracker.jsx [new file with mode: 0644]
resources/js/setup-jest.js [deleted file]
resources/sass/_variables.scss
resources/sass/app.scss
resources/sass/bootstrap.scss
resources/sass/channels.scss
resources/sass/chatlog.scss [new file with mode: 0644]
resources/sass/common.scss
resources/sass/episodes.scss
resources/sass/front.scss
resources/sass/results.scss
resources/sass/rounds.scss
resources/sass/zootr.scss [new file with mode: 0644]
resources/views/app.blade.php
routes/api.php
routes/web.php
tests/Unit/TwitchBot/IRCMessageTest.php
tests/Unit/TwitchBot/TokenizedMessageTest.php
tests/js/helpers/Result.test.js
tests/js/helpers/User.test.js
tests/js/helpers/logic/inverted.test.js
tests/js/helpers/logic/open.test.js
tests/js/helpers/tracker.test.js
vite.config.js [new file with mode: 0644]
webpack.mix.js [deleted file]

index 1671c9b9d94ae80b2d39c6b6a64d154b0ac6cb65..49dd9a03b887df8a23ae51087f658488962135f4 100644 (file)
@@ -4,7 +4,7 @@ root = true
 charset = utf-8
 end_of_line = lf
 insert_final_newline = true
 charset = utf-8
 end_of_line = lf
 insert_final_newline = true
-indent_style = space
+indent_style = tab
 indent_size = 4
 trim_trailing_whitespace = true
 
 indent_size = 4
 trim_trailing_whitespace = true
 
index 956cbc7cae1e9f9010256427e5c6d539896ef61f..1a1fa72972984ec227523661eb3da2c611242475 100644 (file)
@@ -48,8 +48,8 @@ PUSHER_APP_KEY=
 PUSHER_APP_SECRET=
 PUSHER_APP_CLUSTER=mt1
 
 PUSHER_APP_SECRET=
 PUSHER_APP_CLUSTER=mt1
 
-MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
-MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
+VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
+VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
 
 LARASCORD_CLIENT_ID=
 LARASCORD_CLIENT_SECRET=
 
 LARASCORD_CLIENT_ID=
 LARASCORD_CLIENT_SECRET=
@@ -57,7 +57,7 @@ LARASCORD_GRANT_TYPE=authorization_code
 LARASCORD_PREFIX=larascord
 LARASCORD_SCOPE=identify
 
 LARASCORD_PREFIX=larascord
 LARASCORD_SCOPE=identify
 
-MIX_DISCORD_CLIENT_ID="${LARASCORD_CLIENT_ID}"
+VITE_DISCORD_CLIENT_ID="${LARASCORD_CLIENT_ID}"
 
 DISCORD_BOT_TOKEN=
 DISCORD_BOT_CREATE_COMMANDS=
 
 DISCORD_BOT_TOKEN=
 DISCORD_BOT_CREATE_COMMANDS=
index 39965bfd676f89c2b8aae6ee2e9545e264980faf..f44dc8c11222f1c4d40633bd290d1dd01c3dc5d0 100644 (file)
@@ -1,6 +1,7 @@
 /node_modules
 /public/alttp-seeds
 /public/aos-seeds
 /node_modules
 /public/alttp-seeds
 /public/aos-seeds
+/public/build
 /public/css/app.css
 /public/css/app.css.map
 /public/doortracker
 /public/css/app.css
 /public/css/app.css.map
 /public/doortracker
@@ -16,6 +17,7 @@
 .env
 .env.backup
 .env.testing
 .env
 .env.backup
 .env.testing
+.phpunit.cache
 .phpunit.result.cache
 docker-compose.override.yml
 Homestead.json
 .phpunit.result.cache
 docker-compose.override.yml
 Homestead.json
index 656780d143e9f3e62101baf458372fe44d2163a0..90b73d9c7a3021d8ad41b911ac3808e952e4330d 100644 (file)
@@ -4,3 +4,6 @@
 [submodule "public/muffinstracker"]
        path = public/muffinstracker
        url = https://github.com/HolySmoke86/alttptracker.git
 [submodule "public/muffinstracker"]
        path = public/muffinstracker
        url = https://github.com/HolySmoke86/alttptracker.git
+[submodule "public/muffins-smz3"]
+       path = public/muffins-smz3
+       url = https://github.com/HolySmoke86/alttptracker.git
index e492bb7c1169160fafea1c9a938aec7f5b0c8b86..621929db06cc27be54627b5034d2153217fc07c2 100644 (file)
@@ -13,7 +13,7 @@ class ChatlibDatabase extends Command {
         *
         * @var string
         */
         *
         * @var string
         */
-       protected $signature = 'chatlib:database {which=de} {size=7}';
+       protected $signature = 'chatlib:database {which=de} {size=3}';
 
        /**
         * The console command description.
 
        /**
         * The console command description.
@@ -40,14 +40,18 @@ class ChatlibDatabase extends Command {
                        ->whereNotNull('evaluated_at')
                        ->where('created_at', '<', now()->sub(7, 'day'))
                        ->whereNotIn('classification', ['gg', 'gl', 'number', 'o7'])
                        ->whereNotNull('evaluated_at')
                        ->where('created_at', '<', now()->sub(7, 'day'))
                        ->whereNotIn('classification', ['gg', 'gl', 'number', 'o7'])
+                       ->whereNotIn('channel_id', [52, 53])
                        ->where(function ($query) use ($lang) {
                                $query->whereNull('detected_language');
                                $query->orWhere('detected_language', '=', $lang);
                        })
                        ->where(function ($query) use ($lang) {
                                $query->whereNull('detected_language');
                                $query->orWhere('detected_language', '=', $lang);
                        })
-                       ->whereRaw('LENGTH(`text_content`) > 10')
+                       ->orderBy('channel_id')
+                       ->orderBy('created_at')
                        ->chunk(5000, function ($msgs) use (&$count, $db) {
                        ->chunk(5000, function ($msgs) use (&$count, $db) {
+                               $previous = null;
                                foreach ($msgs as $msg) {
                                foreach ($msgs as $msg) {
-                                       $db->addMessage($msg);
+                                       $db->addMessage($msg, $previous);
+                                       $previous = $msg;
                                        ++$count;
                                }
                                $this->line($count);
                                        ++$count;
                                }
                                $this->line($count);
index 04c9e41b63a07887d4f7b78a753807995f2415d5..caa223d51495323e446246c871a3139d0bc825c6 100644 (file)
@@ -12,7 +12,7 @@ class ChatlibGenerate extends Command {
         *
         * @var string
         */
         *
         * @var string
         */
-       protected $signature = 'chatlib:generate {which=de} {amount=50}';
+       protected $signature = 'chatlib:generate {which=de} {amount=50} {context?}';
 
        /**
         * The console command description.
 
        /**
         * The console command description.
@@ -39,7 +39,7 @@ class ChatlibGenerate extends Command {
 
                $amount = intval($this->argument('amount'));
                for ($i = 0; $i < $amount; ++$i) {
 
                $amount = intval($this->argument('amount'));
                for ($i = 0; $i < $amount; ++$i) {
-                       $this->line($db->generate());
+                       $this->line($db->generate($this->argument('context')));
                }
 
                return 0;
                }
 
                return 0;
index 18faf8d49bb72fb9a3fd77a68e93d29f1a8eb29d..769f284ca8cd6e3a9c66a10438d3eba6db32d82b 100644 (file)
@@ -60,6 +60,7 @@ class DiscordBotCommand extends Command
                        $discord->getLoop()->addPeriodicTimer(1, function () use ($discord) {
                                $command = CommandModel::where('status', '=', 'pending')->oldest()->first();
                                if ($command) {
                        $discord->getLoop()->addPeriodicTimer(1, function () use ($discord) {
                                $command = CommandModel::where('status', '=', 'pending')->oldest()->first();
                                if ($command) {
+                                       $this->line('executing command '.$command->id.': '.$command->command);
                                        try {
                                                $command->execute($discord);
                                        } catch (\Exception $e) {
                                        try {
                                                $command->execute($discord);
                                        } catch (\Exception $e) {
index b289bd0bde84b9a36ae92c9a75196f96cc547497..d87179cf665c256b1f16c285ff115a141f72452d 100644 (file)
@@ -32,12 +32,14 @@ class ReevaluateChatCommand extends Command {
                ChatLog::whereIn('type', ['chat', 'error'])
                        ->where('banned', false)
                        ->orderBy('created_at')
                ChatLog::whereIn('type', ['chat', 'error'])
                        ->where('banned', false)
                        ->orderBy('created_at')
-                       ->chunk(10000, function ($logs) use (&$good, &$bad) {
+                       ->chunk(5000, function ($logs) use (&$good, &$bad) {
                                foreach ($logs as $line) {
                                        try {
                                                $line->evaluate();
                                foreach ($logs as $line) {
                                        try {
                                                $line->evaluate();
-                                               $line->evaluated_at = now();
-                                               $line->save();
+                                               if ($line->isDirty()) {
+                                                       $line->evaluated_at = now();
+                                                       $line->save();
+                                               }
                                                ++$good;
                                        } catch (\Exception $e) {
                                                ++$bad;
                                                ++$good;
                                        } catch (\Exception $e) {
                                                ++$bad;
diff --git a/app/Console/Commands/SyncCabookey.php b/app/Console/Commands/SyncCabookey.php
new file mode 100644 (file)
index 0000000..83febfd
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\Episode;
+use App\Models\EpisodePlayer;
+use App\Models\Event;
+use App\Models\User;
+use Carbon\Carbon;
+use Illuminate\Console\Command;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Facades\Http;
+
+class SyncCabookey extends Command {
+
+       /**
+        * The name and signature of the console command.
+        *
+        * @var string
+        */
+       protected $signature = 'sync:cabookey';
+
+       /**
+        * The console command description.
+        *
+        * @var string
+        */
+       protected $description = 'Synchronize Cabookey schedule';
+
+       /**
+        * Execute the console command.
+        *
+        * @return int
+        */
+       public function handle() {
+               $events = Event::where('external_schedule', '=', 'cabookey')
+                       ->where(function (Builder $query) {
+                               $query->whereNull('end');
+                               $query->orWhere('end', '>', now());
+                       })
+                       ->get();
+
+               if (empty($events)) {
+                       return Command::SUCCESS;
+               }
+
+               $schedule = Http::get('https://sheets.googleapis.com/v4/spreadsheets/1Ba4Mnuml11dqd7uSrtSNn6zdWgJ_GZ9e9FRkc_kM1Uw/values/Form Responses 1', [
+                       'alt' => 'json',
+                       'key' => config('google.api_key'),
+               ])->json();
+
+               foreach ($events as $event) {
+                       try {
+                               $this->line('syncing '.$event->name);
+                               $this->syncEvent($event, $schedule['values']);
+                       } catch (\Exception $e) {
+                               $this->error('error syncing event '.$event->name.': '.$e->getMessage());
+                       }
+               }
+
+               return Command::SUCCESS;
+       }
+
+       private function syncEvent(Event $event, $schedule) {
+               for ($i = 1; $i < count($schedule); ++$i) {
+                       $this->syncSchedule($event, $schedule[$i]);
+               }
+       }
+
+       private function syncSchedule(Event $event, $row) {
+               $ext_id = 'cabookey:'.$row[0];
+               $episode = Episode::firstWhere('ext_id', '=', $ext_id);
+               if (!$episode) {
+                       $episode = new Episode();
+                       $episode->ext_id = $ext_id;
+               }
+               $episode->event()->associate($event);
+               $episode->title = 'Cabookey';
+               $start = Carbon::createFromFormat('m/d/Y h:i:s A', $row[5].' '.$row[6], 'America/Detroit')->setTimezone('UTC');
+               if (!$episode->start || $start->ne($episode->start)) {
+                       $episode->start = $start;
+               }
+               $episode->estimate = 90 * 60;
+               $episode->confirmed = true;
+               $episode->save();
+               $this->syncPlayer($episode, $row[1], $row[2]);
+               $this->syncPlayer($episode, $row[3], $row[4]);
+       }
+
+       private function syncPlayer(Episode $episode, $discord, $twitch) {
+               $ext_id = 'cabookey:'.$discord.'-'.$twitch;
+               $player = $episode->players()->firstWhere('ext_id', '=', $ext_id);
+               if (!$player) {
+                       $player = new EpisodePlayer();
+                       $player->ext_id = $ext_id;
+                       $player->episode()->associate($episode);
+               }
+               $user = $this->getUser($discord, $twitch);
+               if ($user) {
+                       $player->user()->associate($user);
+               } else {
+                       $player->user()->disassociate();
+                       $player->name_override = $twitch;
+               }
+               $player->save();
+               return $player;
+       }
+
+       private function getUser($discord, $twitch) {
+               $user = User::firstWhere('discord_nickname', 'LIKE', $discord);
+               if ($user) {
+                       return $user;
+               }
+               $user = User::firstWhere('username', 'LIKE', $discord);
+               if ($user) {
+                       return $user;
+               }
+               $user = User::firstWhere('stream_link', 'LIKE', '%/'.$twitch);
+               if ($user) {
+                       return $user;
+               }
+               $user = User::firstWhere('username', 'LIKE', $twitch);
+               if ($user) {
+                       return $user;
+               }
+               return null;
+       }
+
+}
index e6f800fea86a7c0641a1d95808786c7895bf2476..82450d10327db1b342697c7d3bc99c3961b7b9ed 100644 (file)
@@ -58,7 +58,7 @@ class SyncLadder extends Command {
                foreach ($ladderSchedule as $ladderEntry) {
                        try {
                                $this->syncSchedule($event, $ladderEntry);
                foreach ($ladderSchedule as $ladderEntry) {
                        try {
                                $this->syncSchedule($event, $ladderEntry);
-                       } catch (Exception $e) {
+                       } catch (\Exception $e) {
                                $this->error('error syncing episode '.$ladderEntry['race_id'].': '.$e->getMessage());
                        }
                }
                                $this->error('error syncing episode '.$ladderEntry['race_id'].': '.$e->getMessage());
                        }
                }
index 03337df6769455e71fe651a1a0995b1f73d7426f..854897e305a054f5f0be46310ad0a75e01a58cda 100644 (file)
@@ -56,12 +56,12 @@ class SyncRacetime extends Command {
                $racerooms = $this->getRacetime($event->racetime_category);
                foreach ($episodes as $episode) {
                        $rooms = $this->filterID($episode, $racerooms);
                $racerooms = $this->getRacetime($event->racetime_category);
                foreach ($episodes as $episode) {
                        $rooms = $this->filterID($episode, $racerooms);
-                       //if (count($rooms) > 1) {
-                       //      $rooms = $this->filterStartTime($episode, $rooms);
-                       //}
                        if (count($rooms) > 1) {
                                $rooms = $this->filterPlayerNames($episode, $rooms);
                        }
                        if (count($rooms) > 1) {
                                $rooms = $this->filterPlayerNames($episode, $rooms);
                        }
+                       if (count($rooms) > 1) {
+                               $rooms = $this->filterStartTime($episode, $rooms);
+                       }
                        if (count($rooms) == 1) {
                                $this->line(' - linking episode '.$episode->id.' with room '.$rooms[0]['name']);
                                $episode->raceroom = 'https://racetime.gg'.$rooms[0]['url'];
                        if (count($rooms) == 1) {
                                $this->line(' - linking episode '.$episode->id.' with room '.$rooms[0]['name']);
                                $episode->raceroom = 'https://racetime.gg'.$rooms[0]['url'];
index 41286ce95f2971ece8ce61877f9540214dd9a6e8..6e673ad97dbd529f6eaec167fae7c0ab2ec39ee5 100644 (file)
@@ -85,7 +85,8 @@ class SyncSpeedGaming extends Command {
                $to_purge = $event->episodes()
                        ->where('start', '>=', $from)
                        ->where('start', '<=', $to)
                $to_purge = $event->episodes()
                        ->where('start', '>=', $from)
                        ->where('start', '<=', $to)
-                       ->whereNotIn('ext_id', $ext_ids);
+                       ->whereNotIn('ext_id', $ext_ids)
+                       ->where('ext_id', 'LIKE', 'sg:%');
                foreach ($to_purge->get() as $episode) {
                        $episode->channels()->detach();
                        $episode->crew()->delete();
                foreach ($to_purge->get() as $episode) {
                        $episode->channels()->detach();
                        $episode->crew()->delete();
@@ -207,7 +208,7 @@ class SyncSpeedGaming extends Command {
                }
                $channel->short_name = $sgChannel['initials'];
                $channel->title = $sgChannel['name'];
                }
                $channel->short_name = $sgChannel['initials'];
                $channel->title = $sgChannel['name'];
-               $channel->stream_link = 'https://twitch.tv/'.strtolower($sgChannel['name']);
+               $channel->stream_link = 'https://twitch.tv/'.strtolower($sgChannel['slug']);
                $channel->languages = [$sgChannel['language']];
                $channel->save();
                return $channel;
                $channel->languages = [$sgChannel['language']];
                $channel->save();
                return $channel;
diff --git a/app/Console/Commands/SyncStepLadder.php b/app/Console/Commands/SyncStepLadder.php
new file mode 100644 (file)
index 0000000..b44b843
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\Episode;
+use App\Models\Event;
+use App\Models\StepLadderMode;
+use Carbon\Carbon;
+use Illuminate\Console\Command;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Facades\Http;
+
+
+class SyncStepLadder extends Command {
+
+       /**
+        * The name and signature of the console command.
+        *
+        * @var string
+        */
+       protected $signature = 'sync:stepladder';
+
+       /**
+        * The console command description.
+        *
+        * @var string
+        */
+       protected $description = 'Synchronize Step Ladder schedule';
+
+
+       /**
+        * Execute the console command.
+        *
+        * @return int
+        */
+       public function handle() {
+               $events = Event::where('external_schedule', 'LIKE', 'stepladder')
+                       ->where(function (Builder $query) {
+                               $query->whereNull('end');
+                               $query->orWhere('end', '>', now());
+                       })
+                       ->get();
+
+               foreach ($events as $event) {
+                       try {
+                               $this->line('syncing '.$event->name);
+                               $this->syncEvent($event);
+                       } catch (\Exception $e) {
+                               $this->error('error syncing event '.$event->name.': '.$e->getMessage());
+                       }
+               }
+       }
+
+       private function syncEvent(Event $event) {
+               $ladderSchedule = Http::get('https://alttpr.racing/api/v1/upcoming')->json();
+               foreach ($ladderSchedule as $ladderEntry) {
+                       try {
+                               $this->syncSchedule($event, $ladderEntry);
+                       } catch (\Exception $e) {
+                               $this->error('error syncing episode '.$ladderEntry['id'].': '.$e->getMessage());
+                       }
+               }
+       }
+
+       private function syncSchedule(Event $event, $ladderEntry) {
+               $ext_id = 'stepladder:'.$ladderEntry['id'];
+               $episode = Episode::firstWhere('ext_id', '=', $ext_id);
+               if (!$episode) {
+                       $episode = new Episode();
+                       $episode->ext_id = $ext_id;
+               }
+               $mode = $this->getMode($ladderEntry);
+               $episode->event()->associate($event);
+               $episode->title = $mode->name;
+               $episode->start = Carbon::createFromTimestamp($ladderEntry['time']);
+               $episode->estimate = 2 * 60 * 60;
+               $episode->confirmed = true;
+               $episode->save();
+       }
+
+       private function getMode($ladderEntry) {
+               $ext_id = 'stepladder:'.$ladderEntry['mode'];
+               $mode = StepLadderMode::firstWhere('ext_id', '=', $ext_id);
+               if (!$mode) {
+                       $ladderMode = Http::get('https://alttpr.racing/api/v1/modes/'.$ladderEntry['mode'])->json();
+                       $mode = new StepLadderMode();
+                       $mode->ext_id = $ext_id;
+                       $mode->name = $ladderMode['name'];
+                       $mode->last_sync = Carbon::now();
+                       $mode->save();
+               }
+               return $mode;
+       }
+
+}
diff --git a/app/Console/Commands/SyncStepLadderFull.php b/app/Console/Commands/SyncStepLadderFull.php
new file mode 100644 (file)
index 0000000..a81033f
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\Episode;
+use App\Models\Event;
+use App\Models\StepLadderMode;
+use Carbon\Carbon;
+use Illuminate\Console\Command;
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Support\Facades\Http;
+
+
+class SyncStepLadderFull extends Command {
+
+       /**
+        * The name and signature of the console command.
+        *
+        * @var string
+        */
+       protected $signature = 'sync:stepladderfull';
+
+       /**
+        * The console command description.
+        *
+        * @var string
+        */
+       protected $description = 'Synchronize complete Step Ladder schedule';
+
+
+       /**
+        * Execute the console command.
+        *
+        * @return int
+        */
+       public function handle() {
+               $events = Event::where('external_schedule', 'LIKE', 'stepladder')
+                       ->where(function (Builder $query) {
+                               $query->whereNull('end');
+                               $query->orWhere('end', '>', now());
+                       })
+                       ->get();
+
+               foreach ($events as $event) {
+                       try {
+                               $this->line('syncing '.$event->name);
+                               $this->syncEvent($event);
+                       } catch (\Exception $e) {
+                               $this->error('error syncing event '.$event->name.': '.$e->getMessage());
+                       }
+               }
+       }
+
+       private function syncEvent(Event $event) {
+               $ladderSchedule = Http::get('https://alttpr.racing/api/v1/schedule')->json();
+               foreach ($ladderSchedule as $ladderEntry) {
+                       try {
+                               $this->syncSchedule($event, $ladderEntry);
+                       } catch (\Exception $e) {
+                               $this->error('error syncing episode '.$ladderEntry['id'].': '.$e->getMessage());
+                       }
+               }
+       }
+
+       private function syncSchedule(Event $event, $ladderEntry) {
+               $ext_id = 'stepladder:'.$ladderEntry['id'];
+               $episode = Episode::firstWhere('ext_id', '=', $ext_id);
+               if (!$episode) {
+                       $episode = new Episode();
+                       $episode->ext_id = $ext_id;
+               }
+               $mode = $this->getMode($ladderEntry);
+               $episode->event()->associate($event);
+               $episode->title = $mode->name;
+               $episode->start = Carbon::createFromFormat('Y-m-d H:i:s', $ladderEntry['time'], 'America/Detroit')->setTimezone('UTC');
+               $episode->estimate = 2 * 60 * 60;
+               $episode->confirmed = true;
+               $episode->save();
+       }
+
+       private function getMode($ladderEntry) {
+               $ext_id = 'stepladder:'.$ladderEntry['mode'];
+               $mode = StepLadderMode::firstWhere('ext_id', '=', $ext_id);
+               if (!$mode) {
+                       $ladderMode = Http::get('https://alttpr.racing/api/v1/modes/'.$ladderEntry['mode'])->json();
+                       $mode = new StepLadderMode();
+                       $mode->ext_id = $ext_id;
+                       $mode->name = $ladderMode['name'];
+                       $mode->last_sync = Carbon::now();
+                       $mode->save();
+               }
+               return $mode;
+       }
+
+}
index 1d9211025020e204b7f5dd5a725c800d1f0e578b..9c3b8abbc8d2be9eaf54e3eba463e25bc75877a7 100644 (file)
@@ -41,7 +41,7 @@ class SyncZSR extends Command {
                $events = Event::where('external_schedule', 'LIKE', 'zsr:%')
                        ->where(function (Builder $query) {
                                $query->whereNull('end');
                $events = Event::where('external_schedule', 'LIKE', 'zsr:%')
                        ->where(function (Builder $query) {
                                $query->whereNull('end');
-                               $query->orWhere('end', '<', now());
+                               $query->orWhere('end', '>', now());
                        })
                        ->get();
 
                        })
                        ->get();
 
@@ -88,17 +88,6 @@ class SyncZSR extends Command {
                } else {
                        $episode->title = $entry['summary'];
                }
                } else {
                        $episode->title = $entry['summary'];
                }
-               if (preg_match('/Restream: https?:\/\/(www\.)?twitch\.tv\/(\w+)/u', $entry['description'], $matches)) {
-                       $channel = $this->syncChannel($episode, $matches[2]);
-                       if ($channel) {
-                               $episode->channels()->syncWithoutDetaching([$channel->id]);
-                       }
-               }
-               if (preg_match('/^(.*) - (.*?) vs (.*?)$/u', $episode->title, $matches)) {
-                       $episode->title = $matches[1];
-                       $this->syncPlayer($episode, $matches[2]);
-                       $this->syncPlayer($episode, $matches[3]);
-               }
                $start = Carbon::parse($entry['start']['dateTime'])->setTimezone('UTC');
                if (!$episode->start || $start->ne($episode->start)) {
                        $episode->start = $start;
                $start = Carbon::parse($entry['start']['dateTime'])->setTimezone('UTC');
                if (!$episode->start || $start->ne($episode->start)) {
                        $episode->start = $start;
@@ -106,7 +95,33 @@ class SyncZSR extends Command {
                $end = Carbon::parse($entry['end']['dateTime'])->setTimezone('UTC');
                $episode->estimate = $start->diffInSeconds($end);
                $episode->confirmed = true;
                $end = Carbon::parse($entry['end']['dateTime'])->setTimezone('UTC');
                $episode->estimate = $start->diffInSeconds($end);
                $episode->confirmed = true;
-               $episode->save();
+               if (preg_match('/^(.*) - (.*?) vs\.? (.*?) vs\.? (.*?) vs\.? (.*?)$/u', $episode->title, $matches)) {
+                       $episode->title = $matches[1];
+                       $episode->save();
+                       $this->syncPlayer($episode, $matches[2]);
+                       $this->syncPlayer($episode, $matches[3]);
+                       $this->syncPlayer($episode, $matches[4]);
+                       $this->syncPlayer($episode, $matches[5]);
+               } else if (preg_match('/^(.*) - (.*?) vs\.? (.*?) vs\.? (.*?)$/u', $episode->title, $matches)) {
+                       $episode->title = $matches[1];
+                       $episode->save();
+                       $this->syncPlayer($episode, $matches[2]);
+                       $this->syncPlayer($episode, $matches[3]);
+                       $this->syncPlayer($episode, $matches[4]);
+               } else if (preg_match('/^(.*) - (.*?) vs\.? (.*?)$/u', $episode->title, $matches)) {
+                       $episode->title = $matches[1];
+                       $episode->save();
+                       $this->syncPlayer($episode, $matches[2]);
+                       $this->syncPlayer($episode, $matches[3]);
+               } else {
+                       $episode->save();
+               }
+               if (preg_match('/Restream: https?:\/\/(www\.)?twitch\.tv\/(\w+)/u', $entry['description'], $matches)) {
+                       $channel = $this->syncChannel($episode, $matches[2]);
+                       if ($channel) {
+                               $episode->channels()->syncWithoutDetaching([$channel->id]);
+                       }
+               }
        }
 
        private function syncChannel(Episode $episode, $zsrChannel) {
        }
 
        private function syncChannel(Episode $episode, $zsrChannel) {
index e46c11871bf9738c4c36ee97c401bc3d7102e518..043ad00004b20bddae5009645f7e9925f6c9aae2 100644 (file)
@@ -33,7 +33,7 @@ class TwitchAuth extends Command {
                if (!$token) {
                        $token = new TwitchToken();
                        $token->nick = $this->argument('nick');
                if (!$token) {
                        $token = new TwitchToken();
                        $token->nick = $this->argument('nick');
-                       $token->scope = ['chat:read', 'chat:edit'];
+                       $token->scope = ['chat:read', 'chat:edit', 'whispers:read', 'user:manage:whispers', 'moderator:manage:shoutouts'];
                }
                $url = $token->getAuthUrl();
                $this->line('Please visit '.$url);
                }
                $url = $token->getAuthUrl();
                $this->line('Please visit '.$url);
diff --git a/app/Console/Commands/TwitchChannelClips.php b/app/Console/Commands/TwitchChannelClips.php
new file mode 100644 (file)
index 0000000..be9de00
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\Channel;
+use App\Models\TwitchToken;
+use GuzzleHttp\Psr7\Query;
+use Illuminate\Console\Command;
+use Illuminate\Http\Client\RequestException;
+use Illuminate\Support\Facades\Http;
+
+class TwitchChannelClips extends Command {
+
+       /**
+        * The name and signature of the console command.
+        *
+        * @var string
+        */
+       protected $signature = 'twitch:clips {name}';
+
+       /**
+        * The console command description.
+        *
+        * @var string
+        */
+       protected $description = 'Fetch twitch channel clips';
+
+       /**
+        * Execute the console command.
+        *
+        * @return int
+        */
+       public function handle()
+       {
+               $this->token = TwitchToken::firstWhere('nick', 'localhorsttv');
+               if (!$this->token) {
+                       $this->line('please acquire a token for localhorsttv first');
+                       return 1;
+               }
+               if ($this->token->hasExpired()) {
+                       $this->line('access token has expired, refreshing');
+                       $this->token->refresh();
+               }
+               $channel = Channel::where('title', '=', $this->argument('name'))->firstOrFail();
+               $clips = $this->fetchClips($channel);
+               foreach ($clips as $clip) {
+                       var_dump($clip);
+               }
+               return Command::SUCCESS;
+       }
+
+       private function fetchClips(Channel $channel) {
+               $this->line($channel->twitch_chat);
+               $rsp = $this->token->request()
+                       ->get('/clips', Query::build([
+                               'first' => 100,
+                               'broadcaster_id' => $channel->twitch_id,
+                       ]))
+                       ->throw();
+               return $rsp['data'];
+       }
+
+       private $token;
+
+}
index 7b373c8c94ed54fe611280078158799e35002775..dabc018680e3e275da714929b0e5d251fdba3379 100644 (file)
@@ -88,6 +88,20 @@ class TwitchChannelInfo extends Command {
                foreach ($channels as $channel) {
                        $data = null;
                        foreach ($rsp['data'] as $info) {
                foreach ($channels as $channel) {
                        $data = null;
                        foreach ($rsp['data'] as $info) {
+                               // id => numeric string
+                               // user_id => numeric string
+                               // user_login => string
+                               // user_name => string
+                               // game_id => numeric string
+                               // game_name => string
+                               // type => "live" (or "rerun"?)
+                               // title => string
+                               // viewer_count => int
+                               // started_at => ISO date
+                               // language => 2 letter code
+                               // thumbnail_url => url
+                               // tags [string]
+                               // is_mature => bool
                                if ($info['user_id'] == $channel->twitch_id) {
                                        $data = $info;
                                        break;
                                if ($info['user_id'] == $channel->twitch_id) {
                                        $data = $info;
                                        break;
@@ -99,6 +113,8 @@ class TwitchChannelInfo extends Command {
                        } else {
                                $channel->twitch_live = true;
                                $channel->twitch_category = $data['game_id'];
                        } else {
                                $channel->twitch_live = true;
                                $channel->twitch_category = $data['game_id'];
+                               $channel->twitch_category_name = $data['game_name'];
+                               $channel->twitch_title = $data['title'];
                                $channel->twitch_viewers = $data['viewer_count'];
                        }
                        $channel->save();
                                $channel->twitch_viewers = $data['viewer_count'];
                        }
                        $channel->save();
diff --git a/app/Console/Commands/UnlockRound.php b/app/Console/Commands/UnlockRound.php
new file mode 100644 (file)
index 0000000..3f58fea
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+
+namespace App\Console\Commands;
+
+use App\Events\RoundChanged;
+use App\Models\Protocol;
+use App\Models\Round;
+use Illuminate\Console\Command;
+
+class UnlockRound extends Command
+{
+       /**
+        * The name and signature of the console command.
+        *
+        * @var string
+        */
+       protected $signature = 'round:unlock {round}';
+
+       /**
+        * The console command description.
+        *
+        * @var string
+        */
+       protected $description = 'Unlock the round';
+
+       /**
+        * Execute the console command.
+        *
+        * @return int
+        */
+       public function handle()
+       {
+               $round = Round::findOrFail($this->argument('round'));
+
+               if (!$round->locked) {
+                       $this->line('already unlocked');
+                       return 0;
+               }
+
+               $round->locked = false;
+               $round->save();
+
+               Protocol::roundUnlocked(
+                       $round->tournament,
+                       $round,
+               );
+
+               RoundChanged::dispatch($round);
+
+               return 0;
+       }
+}
index 32e5c8a0afad44f0309ebe55e7fb4995c90ddc45..298dfe53f99f38af5c5409c8c9f921402053d0f8 100644 (file)
@@ -16,9 +16,11 @@ class Kernel extends ConsoleKernel
     protected function schedule(Schedule $schedule)
     {
                $schedule->command('twitch:channel-info')->everyFiveMinutes();
     protected function schedule(Schedule $schedule)
     {
                $schedule->command('twitch:channel-info')->everyFiveMinutes();
-               $schedule->command('sync:ladder')->daily();
+               $schedule->command('sync:stepladder')->daily();
                $schedule->command('sync:speedgaming')->everyFiveMinutes();
                $schedule->command('sync:speedgaming')->everyFiveMinutes();
+               $schedule->command('sync:cabookey')->everyFiveMinutes();
                $schedule->command('sync:sra')->everyFifteenMinutes();
                $schedule->command('sync:sra')->everyFifteenMinutes();
+               $schedule->command('sync:zsr')->everyFifteenMinutes();
                $schedule->command('sync:avatars')->everyFiveMinutes();
                $schedule->command('sync:racetime')->everyFiveMinutes();
                $schedule->command('chat:evaluate 100')->everyMinute();
                $schedule->command('sync:avatars')->everyFiveMinutes();
                $schedule->command('sync:racetime')->everyFiveMinutes();
                $schedule->command('chat:evaluate 100')->everyMinute();
index e6861e03dad79666eaaeb726db05b8d48a862165..61152c1280d97be5455993c6053e07404333bea0 100644 (file)
@@ -3,6 +3,7 @@
 namespace App\DiscordBotCommands;
 
 use App\Models\DiscordBotCommand;
 namespace App\DiscordBotCommands;
 
 use App\Models\DiscordBotCommand;
+use App\Models\DiscordGuild;
 use App\Models\Round;
 use App\Models\User;
 use Discord\Discord;
 use App\Models\Round;
 use App\Models\User;
 use Discord\Discord;
@@ -16,6 +17,8 @@ abstract class BaseCommand {
 
        public static function resolve(Discord $discord, DiscordBotCommand $cmd) {
                switch ($cmd->command) {
 
        public static function resolve(Discord $discord, DiscordBotCommand $cmd) {
                switch ($cmd->command) {
+                       case 'message':
+                               return new MessageCommand($discord, $cmd);
                        case 'presence':
                                return new PresenceCommand($discord, $cmd);
                        case 'result':
                        case 'presence':
                                return new PresenceCommand($discord, $cmd);
                        case 'result':
@@ -42,8 +45,13 @@ abstract class BaseCommand {
                if (isset($this->guild)) {
                        return \React\Promise\resolve($this->guild);
                }
                if (isset($this->guild)) {
                        return \React\Promise\resolve($this->guild);
                }
+               if (is_null($this->command->discord_guild)) {
+                       $g = DiscordGuild::where('guild_id', '=', $this->command->tournament->discord)->firstOrFail();
+                       $this->command->discord_guild()->associate($g);
+                       $this->command->save();
+               }
                return $this->discord->guilds
                return $this->discord->guilds
-                       ->fetch($this->command->tournament->discord)
+                       ->fetch($this->command->discord_guild->guild_id)
                        ->then(function (Guild $guild) {
                                $this->guild = $guild;
                                if ($guild->preferred_locale && !($this->command->tournament && $this->command->tournament->locale)) {
                        ->then(function (Guild $guild) {
                                $this->guild = $guild;
                                if ($guild->preferred_locale && !($this->command->tournament && $this->command->tournament->locale)) {
@@ -64,6 +72,23 @@ abstract class BaseCommand {
                });
        }
 
                });
        }
 
+       protected function fetchParameterChannel() {
+               if (isset($this->parameterChannel)) {
+                       return \React\Promise\resolve($this->parameterChannel);
+               }
+               if (!$this->hasParameter('channel_id')) {
+                       throw new \Exception('missing channel_id parameter');
+               }
+               return $this->fetchGuild()
+                       ->then(function (Guild $guild) {
+                               return $guild->channels->fetch($this->getParameter('channel_id'));
+                       })
+                       ->then(function (Channel $channel) {
+                               $this->parameterChannel = $channel;
+                               return $channel;
+                       });
+       }
+
        protected function fetchRoundChannel() {
                if (isset($this->roundChannel)) {
                        return \React\Promise\resolve($this->roundChannel);
        protected function fetchRoundChannel() {
                if (isset($this->roundChannel)) {
                        return \React\Promise\resolve($this->roundChannel);
@@ -139,6 +164,7 @@ abstract class BaseCommand {
 
        protected $guild = null;
        protected $member = null;
 
        protected $guild = null;
        protected $member = null;
+       protected $parameterChannel = null;
        protected $roundChannel = null;
        protected $user = null;
 
        protected $roundChannel = null;
        protected $user = null;
 
diff --git a/app/DiscordBotCommands/MessageCommand.php b/app/DiscordBotCommands/MessageCommand.php
new file mode 100644 (file)
index 0000000..746bd5f
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+namespace App\DiscordBotCommands;
+
+use App\Models\DiscordBotCommand;
+use Discord\Discord;
+use Discord\Parts\Channel\Channel;
+use Discord\Parts\Channel\Message;
+use Discord\Parts\User\Member;
+
+class MessageCommand extends BaseCommand {
+
+       public function __construct(Discord $discord, DiscordBotCommand $cmd) {
+               parent::__construct($discord, $cmd);
+       }
+
+       public function execute() {
+               if (!$this->hasParameter('text')) {
+                       throw new \Exception('missing text parameter');
+               }
+               return $this->fetchParameterChannel()
+                       ->then(function (Channel $channel) {
+                               $msg = $this->getParameter('text');
+                               return $channel->sendMessage($msg);
+                       });
+       }
+
+}
index a4df19961938f870b2c117821cf2764c6c9845c5..74ba0b15b4852d26c40fa3f51bc2540f5063ea4b 100644 (file)
@@ -23,6 +23,10 @@ class RoundChanged implements ShouldBroadcast
        public function __construct(Round $round)
        {
                $this->round = $round;
        public function __construct(Round $round)
        {
                $this->round = $round;
+               $this->round->setRelations([]);
+               if ($this->round->locked) {
+                       $round->load(['results', 'results.user']);
+               }
        }
 
        /**
        }
 
        /**
index 121ae4e9ce9149fc2162001128dc2943d4a9a004..4de8baa34ce6ca6bad6d04e5c070644f1b359cb6 100644 (file)
@@ -13,20 +13,41 @@ class ChannelController extends Controller {
 
        public function search(Request $request) {
                $validatedData = $request->validate([
 
        public function search(Request $request) {
                $validatedData = $request->validate([
+                       'chatting' => 'boolean|nullable',
                        'id' => 'array',
                        'id.*' => 'integer|numeric',
                        'joinable' => 'boolean|nullable',
                        'id' => 'array',
                        'id.*' => 'integer|numeric',
                        'joinable' => 'boolean|nullable',
+                       'joined' => 'boolean|nullable',
+                       'limit' => 'numeric|nullable',
+                       'logging' => 'boolean|nullable',
                        'manageable' => 'boolean|nullable',
                        'phrase' => 'string|nullable',
                ]);
 
                        'manageable' => 'boolean|nullable',
                        'phrase' => 'string|nullable',
                ]);
 
+               $limit = isset($validatedData['limit']) ? $validatedData['limit'] : 100;
+
                $channels = Channel::query();
                if (!empty($validatedData['id'])) {
                        $channels = $channels->whereIn('id', $validatedData['id']);
                }
                $channels = Channel::query();
                if (!empty($validatedData['id'])) {
                        $channels = $channels->whereIn('id', $validatedData['id']);
                }
+               if (isset($validatedData['chatting'])) {
+                       $channels = $channels->where('chat', '=', !!$validatedData['chatting']);
+               }
                if (isset($validatedData['joinable']) && $validatedData['joinable']) {
                        $channels = $channels->where('twitch_chat', '!=', '');
                }
                if (isset($validatedData['joinable']) && $validatedData['joinable']) {
                        $channels = $channels->where('twitch_chat', '!=', '');
                }
+               if (isset($validatedData['joined'])) {
+                       $channels = $channels->where('join', '=', !!$validatedData['joined']);
+               }
+               if (isset($validatedData['logging'])) {
+                       if (!!$validatedData['logging']) {
+                               $channels = $channels->where('chat', '=', true);
+                               $channels = $channels->orWhere('join', '=', true);
+                       } else {
+                               $channels = $channels->where('chat', '=', false);
+                               $channels = $channels->where('join', '=', false);
+                       }
+               }
                if (isset($validatedData['manageable']) && $validatedData['manageable']) {
                        $user = $request->user();
                        if (!$user) {
                if (isset($validatedData['manageable']) && $validatedData['manageable']) {
                        $user = $request->user();
                        if (!$user) {
@@ -40,7 +61,11 @@ class ChannelController extends Controller {
                        $channels = $channels->where('title', 'LIKE', '%'.$validatedData['phrase'].'%')
                                ->orWhere('short_name', 'LIKE', '%'.$validatedData['phrase'].'%');
                }
                        $channels = $channels->where('title', 'LIKE', '%'.$validatedData['phrase'].'%')
                                ->orWhere('short_name', 'LIKE', '%'.$validatedData['phrase'].'%');
                }
-               $channels = $channels->limit(5);
+               $channels
+                       ->orderBy('twitch_live', 'DESC')
+                       ->orderBy('twitch_viewers', 'DESC')
+                       ->orderBy('title', 'ASC')
+                       ->limit($limit);
                return $this->sendChannels($channels->get());
        }
 
                return $this->sendChannels($channels->get());
        }
 
diff --git a/app/Http/Controllers/ChatBotLogController.php b/app/Http/Controllers/ChatBotLogController.php
new file mode 100644 (file)
index 0000000..62c2885
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\ChatBotLog;
+use App\Models\ChatLog;
+use Carbon\Carbon;
+use Illuminate\Http\Request;
+
+class ChatBotLogController extends Controller {
+
+       public function search(Request $request) {
+               $logs = ChatBotLog::with(['channel', 'origin', 'user'])->orderBy('created_at', 'DESC')->limit(50);
+               return $logs->get()->toJson();
+       }
+
+       public function getContext(ChatBotLog $entry) {
+               $log = ChatLog::where('command', '=', 'PRIVMSG')
+                       ->where('channel_id', '=', $entry->channel_id)
+                       ->where('created_at', '<=', $entry->created_at)
+                       ->orderBy('created_at', 'DESC')
+                       ->limit(10)
+                       ->get()
+                       ->reverse()
+                       ->values();
+               $original = null;
+               if ($entry->origin_id) {
+                       try {
+                               $original = ChatLog::where('command', '=', 'PRIVMSG')
+                                       ->where('channel_id', '=', $entry->origin->channel_id)
+                                       ->where('id', '<', $entry->origin_id)
+                                       ->orderBy('created_at', 'DESC')
+                                       ->limit(10)
+                                       ->get()
+                                       ->reverse()
+                                       ->values();
+                       } catch (\Exception $e) {
+                               // original was deleted perhaps
+                       }
+               }
+               return [
+                       'current' => $log,
+                       'original' => $original,
+               ];
+       }
+
+}
diff --git a/app/Http/Controllers/DiscordBotController.php b/app/Http/Controllers/DiscordBotController.php
new file mode 100644 (file)
index 0000000..99a1b4c
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use App\Models\DiscordBotCommand;
+use App\Models\DiscordChannel;
+use App\Models\DiscordGuild;
+use Illuminate\Http\Request;
+
+class DiscordBotController extends Controller
+{
+
+       public function sendMessage(Request $request, DiscordGuild $guild) {
+               $this->authorize('manage', $guild);
+               $validatedData = $request->validate([
+                       'channel' => 'required|exists:App\\Models\\DiscordChannel,id',
+                       'text' => 'string',
+               ]);
+               $channel = DiscordChannel::findOrFail($validatedData['channel']);
+               $this->authorize('manage', $channel->guild);
+               $cmd = DiscordBotCommand::sendMessage($channel, $validatedData['text']);
+               return $cmd->toJson();
+       }
+
+}
diff --git a/app/Http/Controllers/DiscordController.php b/app/Http/Controllers/DiscordController.php
deleted file mode 100644 (file)
index 1625e32..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-<?php
-
-namespace App\Http\Controllers;
-
-use App\Models\User;
-use App\Providers\RouteServiceProvider;
-use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Auth;
-use Illuminate\Support\Facades\Http;
-
-class DiscordController extends \Jakyeru\Larascord\Http\Controllers\DiscordController
-{
-
-       /**
-        * Handles the Discord OAuth2 login.
-        *
-        * @param Request $request
-        * @return \Illuminate\Http\JsonResponse
-        */
-       public function handle(Request $request)//: \Illuminate\Http\JsonResponse
-       {
-               // Checking if the authorization code is present in the request.
-               if ($request->missing('code')) {
-                       if (env('APP_DEBUG')) {
-                               return response()->json([
-                                       'larascord_message' => config('larascord.error_messages.missing_code', 'The authorization code is missing.'),
-                                       'code' => 400
-                               ]);
-                       } else {
-                               return redirect('/')->with('error', config('larascord.error_messages.missing_code', 'The authorization code is missing.'));
-                       }
-               }
-
-               // Getting the access_token from the Discord API.
-               try {
-                       $accessToken = $this->getDiscordAccessToken($request->get('code'));
-               } catch (\Exception $e) {
-                       if (env('APP_DEBUG')) {
-                               return response()->json([
-                                       'larascord_message' => config('larascord.error_messages.invalid_code', 'The authorization code is invalid.'),
-                                       'message' => $e->getMessage(),
-                                       'code' => $e->getCode()
-                               ]);
-                       } else {
-                               return redirect('/')->with('error', config('larascord.error_messages.invalid_code', 'The authorization code is invalid.'));
-                       }
-               }
-
-               // Using the access_token to get the user's Discord ID.
-               try {
-                       $user = $this->getDiscordUser($accessToken->access_token);
-               } catch (\Exception $e) {
-                       if (env('APP_DEBUG')) {
-                               return response()->json([
-                                       'larascord_message' => config('larascord.error_messages.authorization_failed', 'The authorization failed.'),
-                                       'message' => $e->getMessage(),
-                                       'code' => $e->getCode()
-                               ]);
-                       } else {
-                               return redirect('/')->with('error', config('larascord.error_messages.authorization_failed', 'The authorization failed.'));
-                       }
-               }
-
-               // Making sure the current logged-in user's ID is matching the ID retrieved from the Discord API.
-               if (Auth::check() && (Auth::id() !== $user->id)) {
-                       Auth::logout();
-                       return redirect('/')->with('error', config('larascord.error_messages.invalid_user', 'The user ID doesn\'t match the logged-in user.'));
-               }
-
-               // Confirming the session in case the user was redirected from the password.confirm middleware.
-               if (Auth::check()) {
-                       $request->session()->put('auth.password_confirmed_at', time());
-               }
-
-               // Trying to create or update the user in the database.
-               try {
-                       $user = $this->createOrUpdateUser($user, $accessToken->refresh_token);
-               } catch (\Exception $e) {
-                       if (env('APP_DEBUG')) {
-                               return response()->json([
-                                       'larascord_message' => config('larascord.error_messages.database_error', 'There was an error while trying to create or update the user.'),
-                                       'message' => $e->getMessage(),
-                                       'code' => $e->getCode()
-                               ]);
-                       } else {
-                               return redirect('/')->with('error', config('larascord.error_messages.database_error', 'There was an error while trying to create or update the user.'));
-                       }
-               }
-
-               // Authenticating the user if the user is not logged in.
-               if (!Auth::check()) {
-                       Auth::login($user);
-               }
-
-               // Redirecting the user to the intended page or to the home page.
-               return redirect()->intended(RouteServiceProvider::HOME);
-       }
-
-       /**
-        * Handles the Discord OAuth2 callback.
-        *
-        * @param string $code
-        * @return object
-        * @throws \Illuminate\Http\Client\RequestException
-        */
-       private function getDiscordAccessToken(string $code): object
-       {
-               $this->tokenData['code'] = $code;
-
-               $response = Http::asForm()->post($this->tokenURL, $this->tokenData);
-
-               $response->throw();
-
-               return json_decode($response->body());
-       }
-
-       /**
-        * Handles the Discord OAuth2 login.
-        *
-        * @param string $access_token
-        * @return object
-        * @throws \Illuminate\Http\Client\RequestException
-        */
-       private function getDiscordUser(string $access_token): object
-       {
-               $response = Http::withToken($access_token)->get($this->apiURLBase);
-
-               $response->throw();
-
-               return json_decode($response->body());
-       }
-
-       /**
-        * Handles the creation or update of the user.
-        *
-        * @param object $user
-        * @param string $refresh_token
-        * @return User
-        * @throws \Exception
-        */
-       private function createOrUpdateUser(object $user, string $refresh_token): User
-       {
-               return User::updateOrCreate(
-                       [
-                               'id' => $user->id,
-                       ],
-                       [
-                               'username' => $user->username,
-                               'discord_nickname' => isset($user->global_name) ? $user->global_name : NULL,
-                               'discriminator' => $user->discriminator,
-                               'email' => isset($user->email) ? $user->email : NULL,
-                               'avatar' => $user->avatar ?: NULL,
-                               'verified' => isset($user->verified) ? $user->verified : 0,
-                               'locale' => $user->locale,
-                               'mfa_enabled' => $user->mfa_enabled,
-                               'refresh_token' => $refresh_token
-                       ]
-               );
-       }
-
-}
index 22ca6dc1309464c370325a41e92ea3f7e6906f77..bfbb8a48f02dbf1549ad40ace4eba4e3106f2878 100644 (file)
@@ -195,6 +195,7 @@ class EpisodeController extends Controller
                        'before' => 'nullable|date',
                        'event' => 'nullable|array',
                        'event.*' => 'numeric',
                        'before' => 'nullable|date',
                        'event' => 'nullable|array',
                        'event.*' => 'numeric',
+                       'eventInvert' => 'boolean',
                        'limit' => 'numeric',
                        'offset' => 'numeric',
                        'reverse' => 'boolean',
                        'limit' => 'numeric',
                        'offset' => 'numeric',
                        'reverse' => 'boolean',
@@ -218,7 +219,11 @@ class EpisodeController extends Controller
                        $episodes = $episodes->where('episodes.start', '<=', $validatedData['before']);
                }
                if (!empty($validatedData['event'])) {
                        $episodes = $episodes->where('episodes.start', '<=', $validatedData['before']);
                }
                if (!empty($validatedData['event'])) {
-                       $episodes = $episodes->whereIn('episodes.event_id', $validatedData['event']);
+                       if (isset($validatedData['eventInvert']) && $validatedData['eventInvert']) {
+                               $episodes = $episodes->whereNotIn('episodes.event_id', $validatedData['event']);
+                       } else {
+                               $episodes = $episodes->whereIn('episodes.event_id', $validatedData['event']);
+                       }
                }
                if ($request->user() && $request->user()->isPrivileged()) {
                        $episodes = $episodes->with(['crew', 'crew.user']);
                }
                if ($request->user() && $request->user()->isPrivileged()) {
                        $episodes = $episodes->with(['crew', 'crew.user']);
index 6b5e48cbe4eb8fdd78c6961aec1fdd5bd6d710fe..c1077b01e0f715fd5ff1a3214526077a77cfea14 100644 (file)
@@ -2,12 +2,23 @@
 
 namespace App\Http\Controllers;
 
 
 namespace App\Http\Controllers;
 
+use App\Models\Round;
 use App\Models\Tournament;
 use App\Models\Tournament;
-use Illuminate\Http\Request;
 
 class ProtocolController extends Controller
 {
 
 
 class ProtocolController extends Controller
 {
 
+       public function forRound(Tournament $tournament, Round $round) {
+               $this->authorize('viewProtocol', $round->tournament);
+               $protocol = $round
+                       ->protocols()
+                       ->with('user')
+                       ->orderBy('created_at', 'desc')
+                       ->limit(150)
+                       ->get();
+               return $protocol->values()->toJson();
+       }
+
        public function forTournament(Tournament $tournament) {
                $this->authorize('viewProtocol', $tournament);
                $protocol = $tournament
        public function forTournament(Tournament $tournament) {
                $this->authorize('viewProtocol', $tournament);
                $protocol = $tournament
index ba57c4b0759f45c33b0bb72fe776ec02cc65a5c7..16327c6fe23dad37add1614820974767a22fdbb7 100644 (file)
@@ -9,6 +9,7 @@ use App\Models\Result;
 use App\Models\Round;
 use App\Models\User;
 use Illuminate\Http\Request;
 use App\Models\Round;
 use App\Models\User;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Gate;
 
 class ResultController extends Controller
 {
 
 class ResultController extends Controller
 {
@@ -68,6 +69,10 @@ class ResultController extends Controller
 
                $result->load('user');
 
 
                $result->load('user');
 
+               if (!Gate::allows('seeResults', $round)) {
+                       $result->hideResult($request->user());
+               }
+
                return $result->toJson();
        }
 
                return $result->toJson();
        }
 
index 8ec2b84d010eb7519f4e1da796b2e7717e8d1e01..050a1cf3998e81a6b5000cbddc9b6f522d50b9e0 100644 (file)
@@ -39,6 +39,21 @@ class RoundController extends Controller
                return $round->toJson();
        }
 
                return $round->toJson();
        }
 
+       public function delete(Request $request, Round $round) {
+               $this->authorize('delete', $round);
+               if (count($round->results) > 0) {
+                       return response('Forbidden', 403);
+               }
+               $round->load('tournament');
+               $round->delete();
+               Protocol::roundDeleted(
+                       $round->tournament,
+                       $round,
+                       $request->user(),
+               );
+               return $round->toJson();
+       }
+
        public function update(Request $request, Round $round) {
                $this->authorize('update', $round);
 
        public function update(Request $request, Round $round) {
                $this->authorize('update', $round);
 
index c538bc447be7cfad8de6b462a89871a5b4e11277..a99108bdd202ba519b9f6fa033b8de5f1fa69586 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace App\Http\Controllers;
 
 
 namespace App\Http\Controllers;
 
+use App\Models\ChatBotLog;
 use App\Models\Episode;
 use App\Models\Event;
 use App\Models\SitemapUrl;
 use App\Models\Episode;
 use App\Models\Event;
 use App\Models\SitemapUrl;
@@ -76,6 +77,13 @@ class SitemapXmlController extends Controller
                        $urls[] = $url;
                }
 
                        $urls[] = $url;
                }
 
+               $url = new SitemapUrl();
+               $url->path = '/horstielog';
+               $url->lastmod = ChatBotLog::latest()->first()->created_at;
+               $url->changefreq = 'hourly';
+               $url->priority = 0.5;
+               $urls[] = $url;
+
                return response()->view('sitemap', [
                        'urls' => $urls,
                ])->header('Content-Type', 'text/xml');
                return response()->view('sitemap', [
                        'urls' => $urls,
                ])->header('Content-Type', 'text/xml');
index 2dc7e51a84ae104597626dd05950b4383c55e873..12289a27690aa58bcc6e7bf16ed2a5cfa1bd42a2 100644 (file)
@@ -9,6 +9,7 @@ use App\Models\Protocol;
 use App\Models\Tournament;
 use Illuminate\Auth\Access\AuthorizationException;
 use Illuminate\Http\Request;
 use App\Models\Tournament;
 use Illuminate\Auth\Access\AuthorizationException;
 use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Gate;
 
 class TournamentController extends Controller
 {
 
 class TournamentController extends Controller
 {
@@ -28,16 +29,15 @@ class TournamentController extends Controller
                $tournament = Tournament::with(
                        'applications',
                        'applications.user',
                $tournament = Tournament::with(
                        'applications',
                        'applications.user',
+                       'description',
                        'participants',
                        'participants.user',
                )->findOrFail($id);
                $this->authorize('view', $tournament);
                $rounds = $tournament->rounds()->with(['results', 'results.user'])->limit(25)->get();
                foreach ($rounds as $round) {
                        'participants',
                        'participants.user',
                )->findOrFail($id);
                $this->authorize('view', $tournament);
                $rounds = $tournament->rounds()->with(['results', 'results.user'])->limit(25)->get();
                foreach ($rounds as $round) {
-                       try {
-                               $this->authorize('seeResults', $round);
-                       } catch (AuthorizationException) {
-                               $round->hideResults();
+                       if (!Gate::allows('seeResults', $round)) {
+                               $round->hideResults($request->user());
                        }
                }
                $json = $tournament->toArray();
                        }
                }
                $json = $tournament->toArray();
@@ -93,10 +93,8 @@ class TournamentController extends Controller
                        ->with(['results', 'results.user'])
                        ->limit(25)->get();
                foreach ($rounds as $round) {
                        ->with(['results', 'results.user'])
                        ->limit(25)->get();
                foreach ($rounds as $round) {
-                       try {
-                               $this->authorize('seeResults', $round);
-                       } catch (AuthorizationException) {
-                               $round->hideResults();
+                       if (!Gate::allows('seeResults', $round)) {
+                               $round->hideResults($request->user());
                        }
                }
                return $rounds->toArray();
                        }
                }
                return $rounds->toArray();
@@ -105,11 +103,15 @@ class TournamentController extends Controller
        public function settings(Request $request, Tournament $tournament) {
                $this->authorize('update', $tournament);
                $validatedData = $request->validate([
        public function settings(Request $request, Tournament $tournament) {
                $this->authorize('update', $tournament);
                $validatedData = $request->validate([
+                       'result_reveal' => 'string|nullable|in:always,finishers,never,participants',
                        'show_numbers' => 'boolean|nullable',
                ]);
                if (array_key_exists('show_numbers', $validatedData)) {
                        $tournament->show_numbers = $validatedData['show_numbers'];
                }
                        'show_numbers' => 'boolean|nullable',
                ]);
                if (array_key_exists('show_numbers', $validatedData)) {
                        $tournament->show_numbers = $validatedData['show_numbers'];
                }
+               if (isset($validatedData['result_reveal'])) {
+                       $tournament->result_reveal = $validatedData['result_reveal'];
+               }
                $tournament->save();
                if ($tournament->wasChanged()) {
                        TournamentChanged::dispatch($tournament);
                $tournament->save();
                if ($tournament->wasChanged()) {
                        TournamentChanged::dispatch($tournament);
index 01b8f06fabeec18bdea89117806b9aea0c39f866..3fe68a532a6b9c88efdaed6f12d9b55b6af51bfa 100644 (file)
@@ -68,18 +68,104 @@ class UserController extends Controller
        }
 
        public function single(Request $request, $id) {
        }
 
        public function single(Request $request, $id) {
-               $user = User::findOrFail($id);
+               $user = is_numeric($id) ? User::findOrFail($id) : User::where('username', '=', $id)->firstOrFail();
                $this->authorize('view', $user);
                $this->authorize('view', $user);
+
+               $validatedData = $request->validate([
+                       'with' => 'array',
+                       'with.*' => 'string|in:episodes_as_comms,episodes_as_crew,episodes_as_setup,episodes_as_tracker,episodes_as_runner',
+               ]);
+
                $user->append('random_quote');
                $user->append('random_quote');
-               $user->load('participation');
-               $user->load('participation.tournament');
-               $user->loadCount('round_first');
-               $user->loadCount('round_second');
-               $user->loadCount('round_third');
-               $user->loadCount('tournament_first');
-               $user->loadCount('tournament_second');
-               $user->loadCount('tournament_third');
-               return $user->toJson();
+               $user->load([
+                       'participation',
+                       'participation.tournament',
+               ]);
+               $user->loadCount([
+                       'round_first',
+                       'round_second',
+                       'round_third',
+                       'tournament_first',
+                       'tournament_second',
+                       'tournament_third',
+               ]);
+
+               $json = $user->toArray();
+
+               if (!empty($validatedData['with'])) {
+                       if (in_array('episodes_as_crew', $validatedData['with'])) {
+                               $json['episodes_as_crew'] = $user->episodes_as_crew()->with([
+                                       'channels',
+                                       'crew' => function ($query) use ($request) {
+                                               $query->where('confirmed', true);
+                                               $query->orWhere('user_id', '=', $request->user()->id);
+                                               $query->orWhereIn('channel_id', $request->user()->channel_crews->pluck('channel_id'));
+                                       },
+                                       'crew.user',
+                                       'event',
+                                       'players',
+                                       'players.user',
+                               ])->orderBy('start', 'DESC')->limit(50)->get();
+                       }
+                       if (in_array('episodes_as_comms', $validatedData['with'])) {
+                               $json['episodes_as_comms'] = $user->episodes_as_comms()->with([
+                                       'channels',
+                                       'crew' => function ($query) use ($request) {
+                                               $query->where('confirmed', true);
+                                               $query->orWhere('user_id', '=', $request->user()->id);
+                                               $query->orWhereIn('channel_id', $request->user()->channel_crews->pluck('channel_id'));
+                                       },
+                                       'crew.user',
+                                       'event',
+                                       'players',
+                                       'players.user',
+                               ])->orderBy('start', 'DESC')->limit(50)->get();
+                       }
+                       if (in_array('episodes_as_setup', $validatedData['with'])) {
+                               $json['episodes_as_setup'] = $user->episodes_as_setup()->with([
+                                       'channels',
+                                       'crew' => function ($query) use ($request) {
+                                               $query->where('confirmed', true);
+                                               $query->orWhere('user_id', '=', $request->user()->id);
+                                               $query->orWhereIn('channel_id', $request->user()->channel_crews->pluck('channel_id'));
+                                       },
+                                       'crew.user',
+                                       'event',
+                                       'players',
+                                       'players.user',
+                               ])->orderBy('start', 'DESC')->limit(50)->get();
+                       }
+                       if (in_array('episodes_as_tracker', $validatedData['with'])) {
+                               $json['episodes_as_tracker'] = $user->episodes_as_tracker()->with([
+                                       'channels',
+                                       'crew' => function ($query) use ($request) {
+                                               $query->where('confirmed', true);
+                                               $query->orWhere('user_id', '=', $request->user()->id);
+                                               $query->orWhereIn('channel_id', $request->user()->channel_crews->pluck('channel_id'));
+                                       },
+                                       'crew.user',
+                                       'event',
+                                       'players',
+                                       'players.user',
+                               ])->orderBy('start', 'DESC')->limit(50)->get();
+                       }
+                       if (in_array('episodes_as_runner', $validatedData['with'])) {
+                               $json['episodes_as_runner'] = $user->episodes_as_runner()->with([
+                                       'channels',
+                                       'crew' => function ($query) use ($request) {
+                                               $query->where('confirmed', true);
+                                               $query->orWhere('user_id', '=', $request->user()->id);
+                                               $query->orWhereIn('channel_id', $request->user()->channel_crews->pluck('channel_id'));
+                                       },
+                                       'crew.user',
+                                       'event',
+                                       'players',
+                                       'players.user',
+                               ])->orderBy('start', 'DESC')->limit(50)->get();
+                       }
+               }
+
+               return $json;
        }
 
 }
        }
 
 }
index f50c267eb8a3cae89bfbba84bada33f682a86862..b4f0c118ba6c02bf19bca75c056239717d327962 100644 (file)
@@ -16,6 +16,7 @@ class Channel extends Model {
 
        public function broadcastOn($event) {
                $channels = [
 
        public function broadcastOn($event) {
                $channels = [
+                       new PublicChannel('Channel'),
                        new PrivateChannel('Channel.'.$this->id),
                ];
                if (!empty($this->access_key)) {
                        new PrivateChannel('Channel.'.$this->id),
                ];
                if (!empty($this->access_key)) {
@@ -55,6 +56,8 @@ class Channel extends Model {
                $source = $this->getChatSetting('source', 'any');
                if (in_array($source, ['catchan', 'chan'])) {
                        $query->where('channel_id', $this->id);
                $source = $this->getChatSetting('source', 'any');
                if (in_array($source, ['catchan', 'chan'])) {
                        $query->where('channel_id', $this->id);
+               } else if ($this->twitch_chat != '#horstiebot') {
+                       $query->whereNotIn('channel_id', [52, 53]);
                }
                if (in_array($source, ['cat', 'catchan'])) {
                        $query->where('twitch_category', $this->twitch_category);
                }
                if (in_array($source, ['cat', 'catchan'])) {
                        $query->where('twitch_category', $this->twitch_category);
@@ -289,11 +292,11 @@ class Channel extends Model {
                'guessing_start' => 'datetime',
                'languages' => 'array',
                'join' => 'boolean',
                'guessing_start' => 'datetime',
                'languages' => 'array',
                'join' => 'boolean',
+               'twitch_live' => 'boolean',
        ];
 
        protected $hidden = [
                'access_key',
        ];
 
        protected $hidden = [
                'access_key',
-               'chat',
                'chat_commands',
                'chat_settings',
                'created_at',
                'chat_commands',
                'chat_settings',
                'created_at',
index a4f1f934b52abea3e0f5422ee47524d9a2fc088b..2819ee07a4881476fc7a7b60fe3683164c732d48 100644 (file)
@@ -2,13 +2,24 @@
 
 namespace App\Models;
 
 
 namespace App\Models;
 
+use Illuminate\Broadcasting\Channel as PublicChannel;
+use Illuminate\Database\Eloquent\BroadcastsEvents;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
 class ChatBotLog extends Model {
 
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
 class ChatBotLog extends Model {
 
+       use BroadcastsEvents;
        use HasFactory;
 
        use HasFactory;
 
+       public function broadcastOn($event) {
+               return new PublicChannel('ChatBotLog');
+       }
+
+       public function broadcastWith($event) {
+               $this->load(['channel', 'origin', 'user']);
+       }
+
        public function channel() {
                return $this->belongsTo(Channel::class);
        }
        public function channel() {
                return $this->belongsTo(Channel::class);
        }
index a87c6a7e0b04978e93b78b06ff028af782f9d052..c2023946c04bf71ff8817dd1ba322d909c6939e1 100644 (file)
@@ -6,61 +6,59 @@ use Illuminate\Support\Facades\Storage;
 
 class ChatLib {
 
 
 class ChatLib {
 
-       public function __construct($size = 7) {
+       public function __construct($size = 3) {
                $this->size = $size;
                $this->size = $size;
-
                $converted = [];
                foreach ($this->categories as $category => $patterns) {
                        $converted_patterns = [];
                        foreach ($patterns as $pattern) {
                                $converted_patterns[] = '/\b'.$pattern.'\b/u';
                        }
                $converted = [];
                foreach ($this->categories as $category => $patterns) {
                        $converted_patterns = [];
                        foreach ($patterns as $pattern) {
                                $converted_patterns[] = '/\b'.$pattern.'\b/u';
                        }
-                       $converted['%'.strtoupper($category).'%'] = $converted_patterns;
+                       $converted[strtoupper($category)] = $converted_patterns;
                }
                $this->categories = $converted;
        }
 
                }
                $this->categories = $converted;
        }
 
-       public function addMessage(ChatLog $msg) {
-               $this->addText($msg->text_content);
+       public function addMessage(ChatLog $msg, ChatLog $previous = null) {
+               if ($msg->isReply()) {
+                       $this->addText($msg->text_content, $msg->getReplyParent());
+               } else if (!is_null($previous)) {
+                       $this->addText($msg->text_content, $previous->text_content);
+               } else {
+                       $this->addText($msg->text_content);
+               }
        }
 
        }
 
-       public function addText($text) {
+       public function addText($text, $context = '') {
                $tokens = $this->tokenize($text);
                $tokens = $this->tokenize($text);
-               if (empty($tokens)) return;
-               $tokens[] = '';
-               foreach ($tokens as $num => $token) {
-                       if ($num === 0) {
-                               $this->addTransition([], $token);
-                       } else {
-                               $start = max(0, $num - $this->size - 1);
-                               $end = $num;
-                               for ($i = $start; $i < $end; ++$i) {
-                                       $this->addTransition(array_slice($tokens, $i, $end - $i), $token);
-                                       if ($end - $i < 5) break;
-                               }
+               for ($i = 0; $i < count($tokens) - $this->size; ++$i) {
+                       $this->addTransition(array_slice($tokens, $i, $this->size), $tokens[$i + $this->size]);
+               }
+               if (!empty($context)) {
+                       $tokens = $this->tokenizeWithContext($text, $context);
+                       $size = min($this->size - 1, count($tokens) - $this->size);
+                       for ($i = 0; $i < $size; ++$i) {
+                               $this->addTransition(array_slice($tokens, $i, $this->size), $tokens[$i + $this->size]);
                        }
                }
        }
 
        public function compile() {
                        }
                }
        }
 
        public function compile() {
-               foreach ($this->transitions as $key => $value) {
-                       $this->transitions[$key] = $this->index($this->transitions[$key]);
-                       if (empty($this->transitions[$key])) {
-                               unset($this->transitions[$key]);
-                       }
+               foreach ($this->transitions as $key => $values) {
+                       $this->transitions[$key] = $this->index($values);
                }
        }
 
                }
        }
 
-       public function generate($limit = 100) {
-               $tokens = [''];
-               $generated = '';
-               while (strlen($generated) < $limit) {
-                       $next = $this->randomNext($tokens);
-                       if ($next === '') break;
-                       $tokens[] = $next;
-                       $generated .= $next;
+       public function generate($context = null) {
+               if (!is_null($context)) {
+                       $tokens = $this->tokenizeWithContext('', $context);
+                       $generated = $this->loop($tokens);
+                       if (!empty($generated)) {
+                               return $generated;
+                       }
                }
                }
-               return $generated;
+               $tokens = $this->tokenize('');
+               return $this->loop($tokens);
        }
 
        public function saveAs($name) {
        }
 
        public function saveAs($name) {
@@ -80,39 +78,28 @@ class ChatLib {
        private function index($arr) {
                $result = [];
                $sum = 0;
        private function index($arr) {
                $result = [];
                $sum = 0;
-               foreach ($arr as $key => $entry) {
-                       $weight = $entry[0];
-                       if ($weight == 1) continue;
+               foreach ($arr as $key => $weight) {
                        $lower = $sum;
                        $sum += $weight;
                        $lower = $sum;
                        $sum += $weight;
-                       $examples = [];
-                       if ($key === ' ') {
-                               $examples = [[' ', 0, 1]];
-                       } else {
-                               $subsum = 0;
-                               foreach ($entry[1] as $example => $subweight) {
-                                       $sublower = $subsum;
-                                       $subsum += $subweight;
-                                       $examples[] = [$example, $sublower, $subsum];
-                               }
-                       }
-                       $result[] = [$key, $lower, $sum, $examples];
+                       $result[] = [$key, $lower, $sum];
                }
                return $result;
        }
 
                }
                return $result;
        }
 
-       private function randomNext($tokens) {
-               $cnt = count($tokens);
-               for ($size = min($this->size, $cnt); $size > 0; --$size) {
-                       $cmb = $this->generalize(array_slice($tokens, -$size));
-                       if (isset($this->transitions[$cmb])) {
-                               $pick = $this->pick($this->transitions[$cmb]);
-                               if (!is_null($pick)) {
-                                       return $this->exampleOf($pick);
-                               }
-                       }
+       private function loop($tokens) {
+               while (count($tokens) < 50) {
+                       $next = $this->randomNext($tokens);
+                       if ($next === ' ') break;
+                       $tokens[] = $next;
                }
                }
-               return '';
+               return $this->untokenize($tokens);
+       }
+
+       private function randomNext($tokens) {
+               $key = $this->makeKey($tokens);
+               if (!isset($this->transitions[$key])) return ' ';
+               $pick = $this->pick($this->transitions[$key]);
+               return $pick[0];
        }
 
        private function pick($options) {
        }
 
        private function pick($options) {
@@ -141,78 +128,62 @@ class ChatLib {
                return $options[$min_index];
        }
 
                return $options[$min_index];
        }
 
-       private function addTransition($state, $next) {
-               $cmb = $this->generalize($state);
-               if (!isset($this->transitions[$cmb])) {
-                       $this->transitions[$cmb] = [];
+       private function addTransition($tokens, $next) {
+               $key = $this->makeKey($tokens);
+               if (!isset($this->transitions[$key])) {
+                       $this->transitions[$key] = [];
                }
                }
-               $this->increment($this->transitions[$cmb], $next);
-       }
-
-       private function increment(&$which, $token) {
-               $generalized = $this->generalize([$token]);
-               if (!isset($which[$generalized])) {
-                       $which[$generalized] = [
-                               1,
-                               [],
-                       ];
-                       $which[$generalized][1][$token] = 1;
+               if (!isset($this->transitions[$key][$next])) {
+                       $this->transitions[$key][$next] = 1;
                } else {
                } else {
-                       ++$which[$generalized][0];
-                       if (!isset($which[$generalized][1][$token])) {
-                               $which[$generalized][1][$token] = 1;
-                       } else {
-                               ++$which[$generalized][1][$token];
-                       }
+                       ++$this->transitions[$key][$next];
                }
        }
 
                }
        }
 
-       private function tokenize($str) {
-               return array_values(array_filter(preg_split('/\b/u', $str), function($token) {
-                       if ($token === '') return false;
-                       if (preg_match('/cheer\d+/u', strtolower($token))) return false;
-                       return true;
-               }));
+       private function splitText($text) {
+               if (trim($text) === '') return [];
+               return preg_split('/\s+/u', $text);
        }
 
        }
 
-       private function generalize($tokens) {
-               $str = '';
-               foreach ($tokens as $token) {
-                       $replaced = preg_replace('/\d+/u', '0', $token);
-                       $replaced = preg_replace('/\s+/u', ' ', $replaced);
-                       $replaced = preg_replace('/(.)\1{2,}/u', '$1$1', $replaced);
-                       $replaced = strtolower($replaced);
-                       foreach ($this->aliases as $canonical => $variants) {
-                               if (in_array($replaced, $variants)) {
-                                       $replaced = $canonical;
-                                       break;
-                               }
-                               if ($replaced === $canonical) {
-                                       break;
-                               }
-                       }
-                       $str .= $replaced;
-               }
+       private function makeKey($tokens) {
+               $key = $this->joinText(array_slice($tokens, $this->size * -1));
+               $key = mb_strtolower($key);
+               $key = str_replace(['.', ',', ':', ';', '!', '?', '^', '+', '-', '"', "'", '(', ')', '[', ']'], '', $key);
+               $key = preg_replace('/\d+/u', '0', $key);
                foreach ($this->categories as $category => $patterns) {
                foreach ($this->categories as $category => $patterns) {
-                       $str = preg_replace($patterns, $category, $str);
+                       $key = preg_replace($patterns, $category, $key);
                }
                }
-               return $str;
+               return $key;
        }
 
        }
 
-       private function exampleOf($pick) {
-               $example = $this->pick($pick[3]);
-               return $example[0];
+       private function joinText($tokens) {
+               return implode(' ', $tokens);
        }
 
        }
 
-       private $size = 7;
-       private $transitions = [];
+       private function untokenize($tokens) {
+               return $this->joinText(array_slice($tokens, $this->size));
+       }
 
 
-       private $aliases = [
-               'chest' => ['kiste'],
-               'einen' => ['n', 'nen'],
-               'musik' => ['mukke'],
-               'schade' => ['schad', 'schaade'],
-       ];
+       private function tokenize($text) {
+               $tokens = $this->splitText($text);
+               $combined = array_merge(array_fill(0, $this->size, ' '), $tokens);
+               if (!empty($tokens)) {
+                       $combined[] = ' ';
+               }
+               return $combined;
+       }
+
+       private function tokenizeWithContext($text, $context) {
+               $combined = $this->tokenize($text);
+               $context_tokens = array_slice($this->splitText($context), $this->size * -1 + 1);
+               for ($i = 0; $i < count($context_tokens); ++$i) {
+                       $combined[$this->size - $i - 2] = $context_tokens[count($context_tokens) - $i - 1];
+               }
+               return $combined;
+       }
+
+       private $size;
+       private $transitions = [];
 
        private $categories = [
                'fail' => [
 
        private $categories = [
                'fail' => [
@@ -358,6 +329,7 @@ class ChatLib {
                'wave' => [
                        'dennsenhi',
                        'dergoawave',
                'wave' => [
                        'dennsenhi',
                        'dergoawave',
+                       'falcnwavehi',
                        'heyguys',
                        'holysm0heyguys',
                        'muftaahey',
                        'heyguys',
                        'holysm0heyguys',
                        'muftaahey',
@@ -372,60 +344,92 @@ class ChatLib {
                        'aga(hnim)?',
                        'armos( knights)?',
                        'arrghus',
                        'aga(hnim)?',
                        'armos( knights)?',
                        'arrghus',
+                       'barinade',
                        'blind',
                        'blind',
-                       'ganon(dorf)?',
+                       'bongo bongo',
+                       '(king )?dodongo',
+                       '(phantom )?ganon(dorf)?',
+                       '(queen )?gohma',
                        'helma',
                        'kholdstare',
                        'lanmo(las)?',
                        'moldorm',
                        'helma',
                        'kholdstare',
                        'lanmo(las)?',
                        'moldorm',
+                       'morpha',
                        'mothula',
                        'mott[ei]',
                        'trinexx',
                        'mothula',
                        'mott[ei]',
                        'trinexx',
+                       'twin ?rov(a|er)',
                        'vit(reous|ty)',
                        'vit(reous|ty)',
+                       'v[ou]lvagin?a',
                ],
 
                'zd' => [
                        'eastern',
                ],
 
                'zd' => [
                        'eastern',
+                       'dm?c',
+                       'deku( tree)?',
                        'desert( palace)?',
                        'desert( palace)?',
+                       'fire ?(temple)?',
+                       'forest ?(temple)?',
                        'gt',
                        'gt',
+                       'gtg',
                        'hera',
                        'hera',
-                       'ice ?(palace)?',
+                       'ice ?(cavern|palace)?',
+                       'jabu ?(jabu)?',
                        '(misery )?mire',
                        'pod',
                        '(misery )?mire',
                        'pod',
+                       'shadow ?(temple)?',
                        'skull ?woods',
                        'skull ?woods',
+                       'spirit ?(temple)?',
                        'swamp',
                        'swamp',
-                       'thieve\'?s\'? ?town',
+                       'thie(f|ve)\'?s\'? ?town',
                        'tr',
                        'tt',
                        'tr',
                        'tt',
+                       'water ?(temple)?',
                ],
 
                'zi' => [
                ],
 
                'zi' => [
+                       '(fire|ice|light) arrows',
+                       '(magic )?beans',
+                       'biggoron|bgs',
                        '(big|small|retro|generic) ?keys?',
                        'b[oö]gen',
                        'bombos',
                        '(big|small|retro|generic) ?keys?',
                        'b[oö]gen',
                        'bombos',
-                       'boots',
+                       'bomb( ?bag|chuus?|s)',
+                       '(hover|iron)? ?boots',
                        'bottle',
                        'bows?',
                        'bugnet',
                        'byrna',
                        'cape',
                        'bottle',
                        'bows?',
                        'bugnet',
                        'byrna',
                        'cape',
+                       '(deku )?(stick|nuts)',
+                       'din\'?s( fire)?',
+                       'double defense',
                        'ether',
                        'ether',
+                       'farore\'?s( wind)?',
                        'flasche',
                        'flippers',
                        'fl[uö]te',
                        'frod',
                        'flasche',
                        'flippers',
                        'fl[uö]te',
                        'frod',
-                       '(gloves?|mitts|handschuhe?)',
+                       'frogs? ?(2|two)?',
+                       '(gloves?|mitts|handschuhe?|strength)',
                        '(half|quarter) ?magic',
                        'hammer',
                        '(half|quarter) ?magic',
                        'hammer',
-                       'hookshot',
+                       '(hook|long)shot',
+                       'hovers',
                        '(ice|fire) ?rod',
                        '(ice|fire) ?rod',
+                       'irons',
+                       'k(okiri)?-?sword',
                        'lampe?',
                        'lampe?',
-                       'laser ?bridge',
+                       'lens( of truth)?',
+                       '(ruto\'?s )letter',
+                       'lights',
+                       'lullaby',
                        'mearl',
                        'mirror',
                        'moon ?pearl',
                        'mushroom',
                        'ocarina',
                        'mearl',
                        'mirror',
                        'moon ?pearl',
                        'mushroom',
                        'ocarina',
+                       'p(er|re)scription',
                        'pilz',
                        'powder',
                        'puder',
                        'pilz',
                        'powder',
                        'puder',
@@ -434,18 +438,25 @@ class ChatLib {
                        '(red|green|blue) ?(goo|potion)',
                        '(red|green|blue|baby) ?mail',
                        '(red|blue|bu|boo|good|bad|both)merang',
                        '(red|green|blue) ?(goo|potion)',
                        '(red|green|blue|baby) ?mail',
                        '(red|blue|bu|boo|good|bad|both)merang',
+                       '(gold|silver)? ?scale',
                        'schaufel',
                        '(gro(ss|ß)er? |kleiner? )?schlüssel',
                        'schwert',
                        'schaufel',
                        '(gro(ss|ß)er? |kleiner? )?schlüssel',
                        'schwert',
+                       '(deku|hylian|mirror)? ?shield',
                        'shovel',
                        'silvers',
                        'shovel',
                        'silvers',
+                       '(slingshot|zwille)',
                        'somaria',
                        'spiegel',
                        'somaria',
                        'spiegel',
+                       'stone( of agony)?',
+                       'storms',
                        'sword',
                        'sword',
+                       '(red|green|blue|goron|zora)? ?tunic',
                ],
 
                'zl' => [
                        'big chest',
                ],
 
                'zl' => [
                        'big chest',
+                       '(bomb ?chuu )?bowling',
                        'bumper( cave)?( ledge)?',
                        '(hyrule)? ?castle ?(tower)?',
                        'catfish',
                        'bumper( cave)?( ledge)?',
                        '(hyrule)? ?castle ?(tower)?',
                        'catfish',
@@ -456,9 +467,15 @@ class ChatLib {
                        'desert( ledge)?',
                        'dig(ging)? ?game',
                        '((back|front) of )?escape',
                        'desert( ledge)?',
                        'dig(ging)? ?game',
                        '((back|front) of )?escape',
+                       '(child|adult)? ?fishing',
+                       '(arrow|chest|fishing) (mini ?)?game',
+                       '(open|storms)? ?grotto',
                        'gyl',
                        'hobo',
                        'hook ?(shot) cave',
                        'gyl',
                        'hobo',
                        'hook ?(shot) cave',
+                       'kak(ariko)',
+                       'lake hylia',
+                       '(laser|rainbow) ?bridge',
                        'lava ?chest',
                        '(light|dark) ?world',
                        'lss',
                        'lava ?chest',
                        '(light|dark) ?world',
                        'lss',
@@ -469,10 +486,14 @@ class ChatLib {
                        'red bomb',
                        'sahasrahla',
                        'sasha',
                        'red bomb',
                        'sahasrahla',
                        'sasha',
+                       'sfm',
+                       '([1-5]0 )?skulls',
                        'sick kid',
                        'stumpy',
                        'tile ?room',
                        'sick kid',
                        'stumpy',
                        'tile ?room',
+                       'temple of time',
                        'torch',
                        'torch',
+                       '(gerudo )?valley',
                        'zora( ledge)?',
                ],
        ];
                        'zora( ledge)?',
                ],
        ];
index 2d43b2f08b008e3684e0b9c0ed6fb0532f8194af..6b525b2fd2d3e101ac38460d9d9bc906cea4c6ae 100644 (file)
@@ -5,8 +5,6 @@ namespace App\Models;
 use App\TwitchBot\TokenizedMessage;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 use App\TwitchBot\TokenizedMessage;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
-use Illuminate\Support\Arr;
-use Illuminate\Support\Str;
 use LanguageDetection\Language;
 
 class ChatLog extends Model {
 use LanguageDetection\Language;
 
 class ChatLog extends Model {
@@ -25,8 +23,24 @@ class ChatLog extends Model {
                return TokenizedMessage::fromLog($this);
        }
 
                return TokenizedMessage::fromLog($this);
        }
 
+       public function isReply() {
+               return !empty($this->tags['reply-parent-msg-body']);
+       }
+
+       public function getReplyParent() {
+               return str_replace('\\s', ' ', $this->tags['reply-parent-msg-body']);
+       }
+
+       public function getReplyParentUser() {
+               return $this->tags['reply-parent-display-name'];
+       }
+
+       public function getText() {
+               return $this->params[1];
+       }
+
        public function getTextWithoutEmotes() {
        public function getTextWithoutEmotes() {
-               $text = $this->text_content;
+               $text = $this->params[1];
                if (isset($this->tags['emotes']) && !empty($this->tags['emotes'])) {
                        $emotes = explode('/', $this->tags['emotes']);
                        foreach ($emotes as $emote) {
                if (isset($this->tags['emotes']) && !empty($this->tags['emotes'])) {
                        $emotes = explode('/', $this->tags['emotes']);
                        foreach ($emotes as $emote) {
@@ -41,6 +55,13 @@ class ChatLog extends Model {
                return trim(preg_replace('/\s+/', ' ', $text));
        }
 
                return trim(preg_replace('/\s+/', ' ', $text));
        }
 
+       public function getTextWithoutReply() {
+               if ($this->isReply()) {
+                       return mb_substr($this->params[1], mb_strlen($this->getReplyParentUser()) + 2);
+               }
+               return $this->params[1];
+       }
+
        public function evaluate() {
                $this->evaluateUser();
                $this->evaluateChannel();
        public function evaluate() {
                $this->evaluateUser();
                $this->evaluateChannel();
@@ -53,8 +74,12 @@ class ChatLog extends Model {
                        $this->type = 'self';
                        return;
                }
                        $this->type = 'self';
                        return;
                }
+               if (!empty($this->params) && $this->params[0] == '#'.$this->nick) {
+                       $this->type = 'owner';
+                       return;
+               }
 
 
-               if ($this->command == 'PRIVMSG') {
+               if ($this->command == 'PRIVMSG' || $this->command == 'WHISPER') {
                        if (static::isKnownBot($this->nick)) {
                                $this->type = 'bot';
                        } else if (substr($this->params[0], 0, 1) == '#') {
                        if (static::isKnownBot($this->nick)) {
                                $this->type = 'bot';
                        } else if (substr($this->params[0], 0, 1) == '#') {
@@ -62,12 +87,13 @@ class ChatLog extends Model {
                        } else {
                                $this->type = 'dm';
                        }
                        } else {
                                $this->type = 'dm';
                        }
-                       $this->text_content = $this->params[1];
+                       $this->text_content = $this->getTextWithoutReply();
                        $this->detectLanguage();
                        $tokenized = $this->tokenize();
                        if ($tokenized->isSpammy()) {
                                $this->banned = true;
                        }
                        $this->detectLanguage();
                        $tokenized = $this->tokenize();
                        if ($tokenized->isSpammy()) {
                                $this->banned = true;
                        }
+                       $this->emote_only = $tokenized->isEmoteOnly();
                        $this->classification = $tokenized->classify();
                        return;
                }
                        $this->classification = $tokenized->classify();
                        return;
                }
@@ -79,11 +105,20 @@ class ChatLog extends Model {
                return in_array(strtolower($nick), [
                        'a_n_i_v',
                        'birrellthesquirrel',
                return in_array(strtolower($nick), [
                        'a_n_i_v',
                        'birrellthesquirrel',
+                       'brokkobot',
+                       'creatisbot',
+                       'duden22',
+                       'fossabot',
                        'funtoon',
                        'funtoon',
+                       'kofistreambot',
+                       'lord_helmut_',
                        'nidbot2000',
                        'nightbot',
                        'nidbot2000',
                        'nightbot',
+                       'phnxtyrolbot',
                        'pokemoncommunitygame',
                        'pokemoncommunitygame',
+                       'raccbutler',
                        'sery_bot',
                        'sery_bot',
+                       'soundalerts',
                        'speedgaming',
                        'starbase47',
                        'streamelements',
                        'speedgaming',
                        'starbase47',
                        'streamelements',
index 7d7c3a88da96b6761a74e943474dd5ef1e6aaa78..8a8b81bc184092cfab9d2eaebdd95f60e4cbcede 100644 (file)
@@ -23,6 +23,23 @@ class DiscordBotCommand extends Model
                ];
                $cmd->status = 'pending';
                $cmd->save();
                ];
                $cmd->status = 'pending';
                $cmd->save();
+               return $cmd;
+       }
+
+       public static function sendMessage(DiscordChannel $channel, $text, User $user = null) {
+               $cmd = new DiscordBotCommand();
+               $cmd->discord_guild_id = $channel->discord_guild_id;
+               if ($user) {
+                       $cmd->user()->associate($user);
+               }
+               $cmd->command = 'message';
+               $cmd->parameters = [
+                       'channel_id' => $channel->channel_id,
+                       'text' => $text,
+               ];
+               $cmd->status = 'pending';
+               $cmd->save();
+               return $cmd;
        }
 
        public static function syncUser($user_id) {
        }
 
        public static function syncUser($user_id) {
@@ -33,6 +50,11 @@ class DiscordBotCommand extends Model
                ];
                $cmd->status = 'pending';
                $cmd->save();
                ];
                $cmd->status = 'pending';
                $cmd->save();
+               return $cmd;
+       }
+
+       public function discord_guild() {
+               return $this->belongsTo(DiscordGuild::class);
        }
 
        public function tournament() {
        }
 
        public function tournament() {
@@ -49,11 +71,10 @@ class DiscordBotCommand extends Model
                try {
                        BaseCommand::resolve($discord, $this)
                                ->execute()
                try {
                        BaseCommand::resolve($discord, $this)
                                ->execute()
-                               ->otherwise(function (\Throwable $e) {
-                                       $this->setException($e);
-                               })
                                ->done(function($v = null) {
                                        $this->setDone();
                                ->done(function($v = null) {
                                        $this->setDone();
+                               }, function (\Throwable $e) {
+                                       $this->setException($e);
                                });
                } catch (\Exception $e) {
                        $this->setException($e);
                                });
                } catch (\Exception $e) {
                        $this->setException($e);
index bcbd12dd32b835a4b71bcabf774a0e6a1e31f424..db0825aa7c3b38007218c0359b59c538420c233e 100644 (file)
@@ -44,6 +44,10 @@ class DiscordGuild extends Model
                $model->channels()->whereNotIn('channel_id', $channel_ids)->delete();
        }
 
                $model->channels()->whereNotIn('channel_id', $channel_ids)->delete();
        }
 
+       public function bot_commands() {
+               return $this->hasMany(DiscordBotCommand::class)->orderBy('created_at', 'DESC');
+       }
+
        public function channels() {
                return $this->hasMany(DiscordChannel::class)->orderBy('position');
        }
        public function channels() {
                return $this->hasMany(DiscordChannel::class)->orderBy('position');
        }
index 60b25f2ad8cd6cd21c4003fc747e40c808e1b132..9c902ce6c44ffef6204eab7d298c0abe99fe6fb7 100644 (file)
@@ -93,6 +93,19 @@ class Protocol extends Model
                ProtocolAdded::dispatch($protocol);
        }
 
                ProtocolAdded::dispatch($protocol);
        }
 
+       public static function roundDeleted(Tournament $tournament, Round $round, User $user) {
+               $protocol = static::create([
+                       'tournament_id' => $tournament->id,
+                       'user_id' => $user->id,
+                       'type' => 'round.delete',
+                       'details' => [
+                               'tournament' => static::tournamentMemo($tournament),
+                               'round' => static::roundMemo($round),
+                       ],
+               ]);
+               ProtocolAdded::dispatch($protocol);
+       }
+
        public static function roundEdited(Tournament $tournament, Round $round, User $user) {
                $protocol = static::create([
                        'tournament_id' => $tournament->id,
        public static function roundEdited(Tournament $tournament, Round $round, User $user) {
                $protocol = static::create([
                        'tournament_id' => $tournament->id,
index 229ac4b9c8e418c5d52cf9de99c33e07122eaf26..ab9f49ffdc838f4039a858144992a1d9cb2dfb3c 100644 (file)
@@ -68,6 +68,15 @@ class Result extends Model
        }
 
 
        }
 
 
+       public function hideResult(User $user = null) {
+               if (!$user || $this->user_id != $user->id) {
+                       $this->makeHidden(['forfeit', 'placement', 'score', 'time']);
+               } else {
+                       $this->makeHidden(['placement', 'score']);
+               }
+       }
+
+
        public function round() {
                return $this->belongsTo(Round::class);
        }
        public function round() {
                return $this->belongsTo(Round::class);
        }
index 7daa77957da58769f332421c6b7840407badb74e..c9435c285867e20e0974fbcc81bb6023806bca95 100644 (file)
@@ -2,16 +2,30 @@
 
 namespace App\Models;
 
 
 namespace App\Models;
 
+use Illuminate\Broadcasting\Channel;
+use Illuminate\Database\Eloquent\BroadcastsEvents;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
 class Round extends Model
 {
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
 class Round extends Model
 {
+       use BroadcastsEvents;
        use HasFactory;
 
        use HasFactory;
 
+       public function protocols() {
+               return $this->tournament->protocols()->where('details->round->id', '=', $this->id);
+       }
+
+       public function broadcastOn($event) {
+               return [
+                       new Channel('Tournament.'.$this->tournament_id),
+               ];
+       }
+
 
        public function isComplete() {
                if (count($this->tournament->participants) == 0) return false;
 
        public function isComplete() {
                if (count($this->tournament->participants) == 0) return false;
+               if ($this->tournament->type == 'open-async') return false;
                if (count($this->results) == 0) return false;
                foreach ($this->tournament->getRunners() as $participant) {
                        $result = $participant->findResult($this);
                if (count($this->results) == 0) return false;
                foreach ($this->tournament->getRunners() as $participant) {
                        $result = $participant->findResult($this);
@@ -87,9 +101,9 @@ class Round extends Model
        }
 
 
        }
 
 
-       public function hideResults() {
+       public function hideResults(User $user = null) {
                foreach ($this->results as $result) {
                foreach ($this->results as $result) {
-                       $result->makeHidden(['forfeit', 'placement', 'score', 'time']);
+                       $result->hideResult($user);
                }
        }
 
                }
        }
 
diff --git a/app/Models/StepLadderMode.php b/app/Models/StepLadderMode.php
new file mode 100644 (file)
index 0000000..8cfec9a
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model;
+
+class StepLadderMode extends Model {
+
+       use HasFactory;
+
+}
index 96e89b8939358aea1b88acfdfa8f1c89270e86aa..44bcaf08c1b460932912cfea6d7e3b03d4888bff 100644 (file)
@@ -2,7 +2,6 @@
 
 namespace App\Models;
 
 
 namespace App\Models;
 
-use App\Events\ParticipantChanged;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
 
@@ -48,7 +47,6 @@ class Tournament extends Model
                }
 
                usort($runners, [Participant::class, 'compareScore']);
                }
 
                usort($runners, [Participant::class, 'compareScore']);
-               $reversed = array_reverse($runners);
                $placement = count($runners);
                $skipped = 0;
                $lastScore = $runners[0]->score;
                $placement = count($runners);
                $skipped = 0;
                $lastScore = $runners[0]->score;
@@ -69,6 +67,10 @@ class Tournament extends Model
                return $this->hasMany(Application::class);
        }
 
                return $this->hasMany(Application::class);
        }
 
+       public function description() {
+               return $this->belongsTo(Technique::class);
+       }
+
        public function participants() {
                return $this->hasMany(Participant::class);
        }
        public function participants() {
                return $this->hasMany(Participant::class);
        }
index db834b7a240ca423141f254a1494fc9916b82c22..6ed6a810098ef8089f0c301f14b5fc1a97f1c62c 100644 (file)
@@ -6,12 +6,13 @@ use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Foundation\Auth\User as Authenticatable;
 use Illuminate\Notifications\Notifiable;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Foundation\Auth\User as Authenticatable;
 use Illuminate\Notifications\Notifiable;
+use Jakyeru\Larascord\Traits\InteractsWithDiscord;
 use Laravel\Sanctum\HasApiTokens;
 
 
 class User extends Authenticatable
 {
 use Laravel\Sanctum\HasApiTokens;
 
 
 class User extends Authenticatable
 {
-       use HasApiTokens, HasFactory, Notifiable;
+       use HasApiTokens, HasFactory, InteractsWithDiscord, Notifiable;
 
        public function findResult(Round $round) {
                foreach ($round->results as $result) {
 
        public function findResult(Round $round) {
                foreach ($round->results as $result) {
@@ -123,6 +124,31 @@ class User extends Authenticatable
                return $this->hasMany(ChannelCrew::class);
        }
 
                return $this->hasMany(ChannelCrew::class);
        }
 
+       public function episodes_as_crew() {
+               return $this
+                       ->belongsToMany(Episode::class, 'episode_crews')
+                       ->wherePivot('episode_crews.confirmed', '=', 1)
+                       ->where('episodes.confirmed', '=', 1);
+       }
+
+       public function episodes_as_comms() {
+               return $this->episodes_as_crew()->wherePivot('episode_crews.role', '=', 'commentary');
+       }
+
+       public function episodes_as_setup() {
+               return $this->episodes_as_crew()->wherePivot('episode_crews.role', '=', 'setup');
+       }
+
+       public function episodes_as_tracker() {
+               return $this->episodes_as_crew()->wherePivot('episode_crews.role', '=', 'tracking');
+       }
+
+       public function episodes_as_runner() {
+               return $this
+                       ->belongsToMany(Episode::class, 'episode_players')
+                       ->where('episodes.confirmed', '=', 1);
+       }
+
        public function participation() {
                return $this->hasMany(Participant::class);
        }
        public function participation() {
                return $this->hasMany(Participant::class);
        }
@@ -195,14 +221,20 @@ class User extends Authenticatable
                'id',
                'username',
                'discord_nickname',
                'id',
                'username',
                'discord_nickname',
+               'global_name',
                'discriminator',
                'email',
                'avatar',
                'verified',
                'discriminator',
                'email',
                'avatar',
                'verified',
+               'banner',
+               'banner_color',
+               'accent_color',
                'locale',
                'mfa_enabled',
                'locale',
                'mfa_enabled',
-               'refresh_token',
+               'premium_type',
+               'public_flags',
                'role',
                'role',
+               'roles',
        ];
 
        /**
        ];
 
        /**
@@ -213,7 +245,6 @@ class User extends Authenticatable
        protected $hidden = [
                'email',
                'mfa_enabled',
        protected $hidden = [
                'email',
                'mfa_enabled',
-               'refresh_token',
                'remember_token',
        ];
 
                'remember_token',
        ];
 
index b4376564029e3418b901b73d1b6d659e1e8b8c33..285138ce5cd7fecfa8345c58e7887e6dc25f0ecd 100644 (file)
@@ -91,4 +91,17 @@ class DiscordGuildPolicy
        {
                return false;
        }
        {
                return false;
        }
+
+       /**
+        * Determine whether the user can perform administrative tasks for the guild.
+        *
+        * @param  \App\Models\User  $user
+        * @param  \App\Models\DiscordGuild  $discordGuild
+        * @return \Illuminate\Auth\Access\Response|bool
+        */
+       public function manage(User $user, DiscordGuild $discordGuild)
+       {
+               return $user->isAdmin() || $discordGuild->owner == $user->id;
+       }
+
 }
 }
index 1f872c57bf054edaaf7de6fbba5ea60857c1e40b..7f53e0fe56a362a01d1d887b8946d50687e0f0bf 100644 (file)
@@ -65,7 +65,7 @@ class RoundPolicy
         */
        public function delete(User $user, Round $round)
        {
         */
        public function delete(User $user, Round $round)
        {
-               return false;
+               return !$round->tournament->locked && $user->isTournamentAdmin($round->tournament) && count($round->results) == 0;
        }
 
        /**
        }
 
        /**
@@ -101,11 +101,23 @@ class RoundPolicy
         */
        public function seeResults(?User $user, Round $round)
        {
         */
        public function seeResults(?User $user, Round $round)
        {
-               return
+               if ($round->tournament->result_reveal == 'always') {
+                       return true;
+               }
+               if (
                        $round->locked ||
                        $round->locked ||
-                       ($user && $user->hasFinished($round)) ||
                        ($user && $user->isTournamentMonitor($round->tournament)) ||
                        ($user && $user->isTournamentMonitor($round->tournament)) ||
-                       $round->isComplete();
+                       $round->isComplete()
+               ) {
+                       return true;
+               }
+               if ($round->tournament->result_reveal == 'finishers') {
+                       return ($user && $user->hasFinished($round));
+               }
+               if ($round->tournament->result_reveal == 'participants') {
+                       return ($user && $user->isRunner($round->tournament));
+               }
+               return false;
        }
 
        /**
        }
 
        /**
index 0f73c06797a79b4694215dbe09a380392e56620f..35ac2783910f5f5a5c0bd0d6c3e85eaed94a4a78 100644 (file)
@@ -93,6 +93,7 @@ class IRCMessage {
                                } else {
                                        $str .= ';';
                                }
                                } else {
                                        $str .= ';';
                                }
+                               // TODO: this may need some kind of encoding?
                                $str .= $name.'=';
                                if (!empty($value)) {
                                        $str .= $value;
                                $str .= $name.'=';
                                if (!empty($value)) {
                                        $str .= $value;
@@ -140,6 +141,13 @@ class IRCMessage {
                return TokenizedMessage::fromIRC($this);
        }
 
                return TokenizedMessage::fromIRC($this);
        }
 
+       public static function capReq($cap) {
+               $msg = new IRCMessage();
+               $msg->command = 'CAP REQ';
+               $msg->params[] = $cap;
+               return $msg;
+       }
+
        public static function join($channels) {
                $msg = new IRCMessage();
                $msg->command = 'JOIN';
        public static function join($channels) {
                $msg = new IRCMessage();
                $msg->command = 'JOIN';
@@ -199,6 +207,14 @@ class IRCMessage {
                return $this->command == 'PRIVMSG';
        }
 
                return $this->command == 'PRIVMSG';
        }
 
+       public function isRoomstate() {
+               return $this->command == 'ROOMSTATE';
+       }
+
+       public function isWhisper() {
+               return $this->command == 'WHISPER';
+       }
+
        public function isOwner() {
                return substr($this->getPrivMsgTarget(), 1) == $this->nick;
        }
        public function isOwner() {
                return substr($this->getPrivMsgTarget(), 1) == $this->nick;
        }
@@ -207,6 +223,14 @@ class IRCMessage {
                return $this->isOwner() || (isset($this->tags['mod']) && $this->tags['mod'] == '1');
        }
 
                return $this->isOwner() || (isset($this->tags['mod']) && $this->tags['mod'] == '1');
        }
 
+       public function hasTag($name) {
+               return array_key_exists($name, $this->tags);
+       }
+
+       public function getTag($name) {
+               return $this->tags[$name];
+       }
+
        public function makePong() {
                $msg = new IRCMessage();
                $msg->command = 'PONG';
        public function makePong() {
                $msg = new IRCMessage();
                $msg->command = 'PONG';
index 4b7d758221d71aa9a9a3d9cbfdd9cf3cde77cb73..ca51451d37d2480930bbe3a9bd5238fdb0b44730 100644 (file)
@@ -3,7 +3,6 @@
 namespace App\TwitchBot;
 
 use App\Models\ChatLog;
 namespace App\TwitchBot;
 
 use App\Models\ChatLog;
-use Illuminate\Support\Arr;
 use Illuminate\Support\Str;
 
 class TokenizedMessage {
 use Illuminate\Support\Str;
 
 class TokenizedMessage {
@@ -11,10 +10,13 @@ class TokenizedMessage {
        public function __construct($text, $tags = []) {
                $this->text = trim($text);
                $this->tags = $tags;
        public function __construct($text, $tags = []) {
                $this->text = trim($text);
                $this->tags = $tags;
+               if (isset($tags['reply-parent-display-name'])) {
+                       $this->text = mb_substr($text, mb_strlen($tags['reply-parent-display-name']) + 2);
+               }
                $this->raw = strtolower(preg_replace('/[^\w]/u', '', $this->text));
                $this->raw = strtolower(preg_replace('/[^\w]/u', '', $this->text));
-               $this->tokens = array_values(array_map('trim', array_filter(preg_split('/\b/u', strtolower($this->text)))));
+               $this->tokens = array_values(array_filter(array_map('trim', array_filter(preg_split('/\b/u', strtolower($this->text))))));
 
 
-               $this->emoteless = $this->text;
+               $this->emoteless = $text;
                if (isset($this->tags['emotes']) && !empty($this->tags['emotes'])) {
                        $emotes = explode('/', $this->tags['emotes']);
                        foreach ($emotes as $emote) {
                if (isset($this->tags['emotes']) && !empty($this->tags['emotes'])) {
                        $emotes = explode('/', $this->tags['emotes']);
                        foreach ($emotes as $emote) {
@@ -31,7 +33,7 @@ class TokenizedMessage {
                        $this->emoteless = trim(preg_replace('/\s+/u', ' ', $this->emoteless));
                }
                $this->emoteless_raw = strtolower(preg_replace('/[^\w]/u', '', $this->emoteless));
                        $this->emoteless = trim(preg_replace('/\s+/u', ' ', $this->emoteless));
                }
                $this->emoteless_raw = strtolower(preg_replace('/[^\w]/u', '', $this->emoteless));
-               $this->emoteless_tokens = array_values(array_map('trim', array_filter(preg_split('/\b/u', strtolower($this->emoteless)))));
+               $this->emoteless_tokens = array_values(array_filter(array_map('trim', array_filter(preg_split('/\b/u', strtolower($this->emoteless))))));
        }
 
        public static function fromIRC(IRCMessage $msg) {
        }
 
        public static function fromIRC(IRCMessage $msg) {
@@ -47,6 +49,11 @@ class TokenizedMessage {
        }
 
 
        }
 
 
+       public function getText() {
+               return $this->text;
+       }
+
+
        public function contains($text) {
                return Str::contains($this->text, $text);
        }
        public function contains($text) {
                return Str::contains($this->text, $text);
        }
@@ -197,6 +204,10 @@ class TokenizedMessage {
                return false;
        }
 
                return false;
        }
 
+       public function isEmoteOnly() {
+               return empty($this->emoteless_raw);
+       }
+
        public function isLong() {
                return strlen($this->emoteless_raw) > 20;
        }
        public function isLong() {
                return strlen($this->emoteless_raw) > 20;
        }
@@ -253,13 +264,22 @@ class TokenizedMessage {
                if ($this->contains(['€', '$', '@', '://'])) {
                        return true;
                }
                if ($this->contains(['€', '$', '@', '://'])) {
                        return true;
                }
-               if ($this->containsRaw(['followers', 'promotion', 'viewers'])) {
+               if ($this->containsRaw(['follow', 'promotion', 'viewer'])) {
                        return true;
                }
                if ($this->containsRaw('horsti')) {
                        return true;
                }
                        return true;
                }
                if ($this->containsRaw('horsti')) {
                        return true;
                }
-               if ($this->containsRaw(['folgtjetzt', 'vielendankfürdenraid', 'thanksfortheraid', 'willkommenaufstarbase47'])) {
+               if ($this->containsRaw([
+                       'folgtjetzt',
+                       'hatdeinenkanalgeraided',
+                       'isnowlivestreaming',
+                       'stürmtdenladenmit',
+                       'thanksfortheraid',
+                       'verschwindetfürneweileindenlurk',
+                       'vielendankfürdenraid',
+                       'willkommenaufstarbase47',
+               ])) {
                        return true;
                }
                return false;
                        return true;
                }
                return false;
@@ -274,7 +294,7 @@ class TokenizedMessage {
                                $this->classification = 'cmd';
                        } else if ($this->isShort() && ($this->hasTokenThatStartsOrEndsWith(['gg']) || $this->hasEmoteThatEndsWith(['gg']))) {
                                $this->classification = 'gg';
                                $this->classification = 'cmd';
                        } else if ($this->isShort() && ($this->hasTokenThatStartsOrEndsWith(['gg']) || $this->hasEmoteThatEndsWith(['gg']))) {
                                $this->classification = 'gg';
-                       } else if ($this->isShort() && $this->containsRaw(['glgl', 'glhf', 'goodluck', 'hfgl', 'vielglück'])) {
+                       } else if ($this->isShort() && ($this->containsRaw(['glgl', 'glhf', 'goodluck', 'hfgl', 'vielglück']) || $this->hasToken('gl'))) {
                                $this->classification = 'gl';
                        } else if ($this->hasToken(['danke', 'thanks', 'thx', 'ty']) && !$this->hasToken(['nah', 'nee', 'nein', 'no'])) {
                                $this->classification = 'thx';
                                $this->classification = 'gl';
                        } else if ($this->hasToken(['danke', 'thanks', 'thx', 'ty']) && !$this->hasToken(['nah', 'nee', 'nein', 'no'])) {
                                $this->classification = 'thx';
@@ -306,7 +326,7 @@ class TokenizedMessage {
                                $this->classification = 'kappa';
                        } else if ($this->startsOrEndsWithRaw(['o7']) || $this->hasEmoteThatContains('salut')) {
                                $this->classification = 'o7';
                                $this->classification = 'kappa';
                        } else if ($this->startsOrEndsWithRaw(['o7']) || $this->hasEmoteThatContains('salut')) {
                                $this->classification = 'o7';
-                       } else if (!$this->isLong() && ($this->containsRaw(['haha', 'hehe', 'hihi', 'kekw', 'lol', 'lul']) || $this->hasTokenThatStartsWith(['xd']) || $this->hasConsecutiveTokens([':', 'd']))) {
+                       } else if (!$this->isLong() && ($this->containsRaw(['dekw', 'haha', 'hehe', 'hihi', 'kekw', 'lol', 'lul']) || $this->hasTokenThatStartsWith(['xd']) || $this->hasConsecutiveTokens([':', 'd']))) {
                                $this->classification = 'lol';
                        } else if (is_numeric($this->raw)) {
                                $this->classification = 'number';
                                $this->classification = 'lol';
                        } else if (is_numeric($this->raw)) {
                                $this->classification = 'number';
@@ -336,9 +356,9 @@ class TokenizedMessage {
                                        $this->hasConsecutiveTokens(['how', 'much']) ||
                                        $this->hasConsecutiveTokens(['wie', 'viele'])
                                ) {
                                        $this->hasConsecutiveTokens(['how', 'much']) ||
                                        $this->hasConsecutiveTokens(['wie', 'viele'])
                                ) {
-                                       return ['yes', 'no', 'kappa', 'lol', 'wtf', 'number'];
+                                       return ['yes', 'no', 'kappa', 'wtf', 'number'];
                                }
                                }
-                               return ['yes', 'no', 'kappa', 'lol', 'wtf'];
+                               return ['yes', 'no', 'kappa', 'wtf'];
                        case 'rage':
                                return ['kappa', 'lol', 'rage'];
                        case 'wtf':
                        case 'rage':
                                return ['kappa', 'lol', 'rage'];
                        case 'wtf':
index 63f4236f685e92bf659610257e93177a78cf7a11..23797cd1d3bda0ddd9912c53935a6994c3c2fbb4 100644 (file)
@@ -118,6 +118,14 @@ class TwitchBot {
                        $this->handlePrivMsg($msg);
                        return;
                }
                        $this->handlePrivMsg($msg);
                        return;
                }
+               if ($msg->isWhisper()) {
+                       $this->handleWhisper($msg);
+                       return;
+               }
+               if ($msg->isRoomstate()) {
+                       $this->handleRoomstate($msg);
+                       return;
+               }
                if ($msg->isNotice() && $msg->getText() == 'Login authentication failed') {
                        $this->logger->notice('login failed, refreshing access token');
                        $this->token->refresh();
                if ($msg->isNotice() && $msg->getText() == 'Login authentication failed') {
                        $this->logger->notice('login failed, refreshing access token');
                        $this->token->refresh();
@@ -130,6 +138,11 @@ class TwitchBot {
                        $this->ready = true;
                        return;
                }
                        $this->ready = true;
                        return;
                }
+               if ($msg->command == 'GLOBALUSERSTATE') {
+                       // receive own user metadata
+                       $this->handleUserState($msg);
+                       return;
+               }
        }
 
        public function getMessageChannel(IRCMessage $msg) {
        }
 
        public function getMessageChannel(IRCMessage $msg) {
@@ -146,6 +159,18 @@ class TwitchBot {
        public function handlePrivMsg(IRCMessage $msg) {
        }
 
        public function handlePrivMsg(IRCMessage $msg) {
        }
 
+       public function handleRoomstate(IRCMessage $msg) {
+       }
+
+       public function handleUserState(IRCMessage $msg) {
+               if (isset($msg->tags['user-id'])) {
+                       $this->user_id = $msg->tags['user-id'];
+               }
+       }
+
+       public function handleWhisper(IRCMessage $msg) {
+       }
+
        public function login() {
                $this->ws->send('PASS oauth:'.$this->token->access);
                $this->ws->send('NICK '.$this->nick);
        public function login() {
                $this->ws->send('PASS oauth:'.$this->token->access);
                $this->ws->send('NICK '.$this->nick);
@@ -172,6 +197,20 @@ class TwitchBot {
                $this->last_contact = time();
        }
 
                $this->last_contact = time();
        }
 
+       public function sendWhisper($to, $msg) {
+               $this->logger->info('sending whisper to '.$to.': '.$msg);
+               try {
+                       $response = $this->token->request()->post('/whispers?from_user_id='.$this->user_id.'&to_user_id='.$to, [
+                               'message' => $msg,
+                       ]);
+                       if (!$response->successful()) {
+                               $this->logger->error('sending whisper to '.$to.': '.$response->status());
+                       }
+               } catch (\Exception $e) {
+                       $this->logger->error('sending whisper to '.$to.': '.$e->getMessage());
+               }
+       }
+
 
        protected function listenCommands() {
                $this->getLoop()->addPeriodicTimer(1, function () {
 
        protected function listenCommands() {
                $this->getLoop()->addPeriodicTimer(1, function () {
@@ -191,6 +230,7 @@ class TwitchBot {
 
        private $nick;
        private $token;
 
        private $nick;
        private $token;
+       private $user_id = '';
 
        private $connector;
        private $ws;
 
        private $connector;
        private $ws;
index 6ec517e93f62ba55926e40b5a6bfa15303a3c9a7..7b505ed8c48341d61d9733934c56b33d3ac3c0ea 100644 (file)
@@ -46,6 +46,22 @@ class TwitchChatBot extends TwitchBot {
                $this->tagChannelRead($channel, $msg);
        }
 
                $this->tagChannelRead($channel, $msg);
        }
 
+       public function handleRoomstate(IRCMessage $msg) {
+               $channel = $this->getMessageChannel($msg);
+               if ($channel && $msg->hasTag('emote-only')) {
+                       $oldEmote = $this->getNote($channel, 'emote_only');
+                       $newEmote = !!intval($msg->getTag('emote-only'));
+                       if ($oldEmote != $newEmote) {
+                               $this->setNote($channel, 'emote_only', $newEmote);
+                       }
+               }
+       }
+
+       public function handleWhisper(IRCMessage $msg) {
+               $text = $this->chatlib->generate($msg->getText());
+               $this->sendWhisper($msg->tags['user-id'], $text);
+       }
+
        public function getChatlibDatabase(Channel $channel) {
                return $this->chatlib;
        }
        public function getChatlibDatabase(Channel $channel) {
                return $this->chatlib;
        }
@@ -80,7 +96,7 @@ class TwitchChatBot extends TwitchBot {
                        return;
                }
                $text = $this->contextualMsg($channel);
                        return;
                }
                $text = $this->contextualMsg($channel);
-               if ($this->shouldAdlib($channel)) {
+               if (!$text && $this->shouldAdlib($channel)) {
                        $this->performAdlib($channel);
                        return;
                }
                        $this->performAdlib($channel);
                        return;
                }
@@ -104,6 +120,7 @@ class TwitchChatBot extends TwitchBot {
        private function getNotes(Channel $channel) {
                if (!isset($this->notes[$channel->id])) {
                        $this->notes[$channel->id] = [
        private function getNotes(Channel $channel) {
                if (!isset($this->notes[$channel->id])) {
                        $this->notes[$channel->id] = [
+                               'emote_only' => false,
                                'last_read' => 0,
                                'last_special' => [],
                                'last_write' => time(),
                                'last_read' => 0,
                                'last_special' => [],
                                'last_write' => time(),
@@ -198,9 +215,12 @@ class TwitchChatBot extends TwitchBot {
        }
 
        private function randomChat(Channel $channel) {
        }
 
        private function randomChat(Channel $channel) {
-               return $channel->queryChatlog()
-                       ->whereNotIn('classification', ['gg', 'gl', 'number', 'o7'])
-                       ->first();
+               $query = $channel->queryChatlog()
+                       ->whereNotIn('classification', ['gg', 'gl', 'number', 'o7']);
+               if ($this->getNote($channel, 'emote_only', false)) {
+                       $query->where('emote_only', '=', true);
+               }
+               return $query->first();
        }
 
        private function randomContextualNumber(Channel $channel) {
        }
 
        private function randomContextualNumber(Channel $channel) {
@@ -253,12 +273,17 @@ class TwitchChatBot extends TwitchBot {
        }
 
        private function randomMsg(Channel $channel) {
        }
 
        private function randomMsg(Channel $channel) {
-               return $channel->queryChatlog()->first();
+               $query = $channel->queryChatlog();
+               if ($this->getNote($channel, 'emote_only', false)) {
+                       $query->where('emote_only', '=', true);
+               }
+               return $query->first();
        }
 
        private function performAdlib(Channel $channel) {
                $db = $this->getChatlibDatabase($channel);
        }
 
        private function performAdlib(Channel $channel) {
                $db = $this->getChatlibDatabase($channel);
-               $text = $db->generate();
+               $latest_msg = $this->getLatestMessage($channel);
+               $text = $db->generate($latest_msg->getText());
                $this->tagChannelWrite($channel);
                $this->sendIRCMessage(IRCMessage::privmsg($channel->twitch_chat, $text));
                $log = new ChatBotLog();
                $this->tagChannelWrite($channel);
                $this->sendIRCMessage(IRCMessage::privmsg($channel->twitch_chat, $text));
                $log = new ChatBotLog();
@@ -306,12 +331,10 @@ class TwitchChatBot extends TwitchBot {
 
                $tokenized = $msg->tokenize();
                if (!ChatLog::isKnownBot($msg->nick) && !$tokenized->isSpammy()) {
 
                $tokenized = $msg->tokenize();
                if (!ChatLog::isKnownBot($msg->nick) && !$tokenized->isSpammy()) {
-                       $this->notes[$channel->id]['latest_msgs'][] = $tokenized;
-                       if (count($this->notes[$channel->id]['latest_msgs']) > 10) {
-                               array_shift($this->notes[$channel->id]['latest_msgs']);
-                       }
+                       $this->noteChannelMessage($channel, $tokenized);
                }
                if ($this->isDirectedAtMe($msg->getText()) && $this->shouldRespond($channel)) {
                }
                if ($this->isDirectedAtMe($msg->getText()) && $this->shouldRespond($channel)) {
+                       $this->noteChannelMessage($channel, $tokenized);
                        $this->notes[$channel->id]['wait_msgs'] = 0;
                        $this->notes[$channel->id]['wait_time'] = 0;
                        $response = $tokenized->getResponseCategory();
                        $this->notes[$channel->id]['wait_msgs'] = 0;
                        $this->notes[$channel->id]['wait_time'] = 0;
                        $response = $tokenized->getResponseCategory();
@@ -321,6 +344,13 @@ class TwitchChatBot extends TwitchBot {
                }
        }
 
                }
        }
 
+       private function noteChannelMessage(Channel $channel, TokenizedMessage $tokenized) {
+               $this->notes[$channel->id]['latest_msgs'][] = $tokenized;
+               if (count($this->notes[$channel->id]['latest_msgs']) > 10) {
+                       array_shift($this->notes[$channel->id]['latest_msgs']);
+               }
+       }
+
        private function tagChannelWrite(Channel $channel) {
                $this->getNotes($channel);
                $this->notes[$channel->id]['last_write'] = time();
        private function tagChannelWrite(Channel $channel) {
                $this->getNotes($channel);
                $this->notes[$channel->id]['last_write'] = time();
@@ -335,7 +365,7 @@ class TwitchChatBot extends TwitchBot {
        }
 
        private function getLatestMessage(Channel $channel) {
        }
 
        private function getLatestMessage(Channel $channel) {
-               $this->getNotes($channel);
+               $notes = $this->getNotes($channel);
                if (!empty($notes['latest_msgs'])) {
                        return $notes['latest_msgs'][count($notes['latest_msgs']) - 1];
                }
                if (!empty($notes['latest_msgs'])) {
                        return $notes['latest_msgs'][count($notes['latest_msgs']) - 1];
                }
diff --git a/ci.sh b/ci.sh
index b57b3b57dd2645a1d8b263b642f5dc81fa7b998c..62b2226b90b6687e60f449a0e5ea2af19b7de9ad 100755 (executable)
--- a/ci.sh
+++ b/ci.sh
@@ -4,6 +4,6 @@ composer -nq install
 php artisan key:generate
 php artisan migrate:fresh
 npm clean-install
 php artisan key:generate
 php artisan migrate:fresh
 npm clean-install
-npm run production
+npm run build
 XDEBUG_MODE=coverage nice php artisan test --without-tty --coverage-html /var/www/coverage/alttp/php
 XDEBUG_MODE=coverage nice php artisan test --without-tty --coverage-html /var/www/coverage/alttp/php
-nice npm run test -- --coverage --coverageDirectory /var/www/coverage/alttp/js --coverageReporters html --collectCoverageFrom 'resources/js/**'
+LARAVEL_BYPASS_ENV_CHECK=1 nice npm run test -- --coverage --coverage.reportsDirectory /var/www/coverage/alttp/js --coverage.reporters html --coverage.include 'resources/js/**'
index 5075d26479c1bd7c7f2c06242488ffe1b3ad2a4d..2501b1642cd2decbd1c3f1dece7bf2c373d7b0c2 100644 (file)
@@ -5,14 +5,13 @@
     "keywords": ["framework", "laravel"],
     "license": "MIT",
     "require": {
     "keywords": ["framework", "laravel"],
     "license": "MIT",
     "require": {
-        "php": "^8.1",
-        "beyondcode/laravel-websockets": "^1.13",
-        "doctrine/dbal": "^3.3",
+        "php": "^8.2",
         "guzzlehttp/guzzle": "^7.2",
         "guzzlehttp/guzzle": "^7.2",
-        "jakyeru/larascord": "^3.0",
-        "laravel/breeze": "^1.4",
-        "laravel/framework": "^10.0",
-        "laravel/sanctum": "^3.2",
+        "jakyeru/larascord": "^6.0",
+        "laravel/breeze": "^2.0",
+        "laravel/framework": "^11.0",
+        "laravel/reverb": "^1.2",
+        "laravel/sanctum": "^4.0",
         "laravel/tinker": "^2.7",
         "laravel/ui": "^4.0",
         "patrickschur/language-detection": "^5.3",
         "laravel/tinker": "^2.7",
         "laravel/ui": "^4.0",
         "patrickschur/language-detection": "^5.3",
@@ -23,8 +22,8 @@
         "fakerphp/faker": "^1.9.1",
         "laravel/sail": "^1.0.1",
         "mockery/mockery": "^1.4.4",
         "fakerphp/faker": "^1.9.1",
         "laravel/sail": "^1.0.1",
         "mockery/mockery": "^1.4.4",
-        "nunomaduro/collision": "^6.1",
-        "phpunit/phpunit": "^9.5.10",
+        "nunomaduro/collision": "^8.1",
+        "phpunit/phpunit": "^11.0",
         "spatie/laravel-ignition": "^2.0"
     },
     "autoload": {
         "spatie/laravel-ignition": "^2.0"
     },
     "autoload": {
index 01da47070748d8e1804b18d8abd7fa1c8ec1a1af..b9b0f90d326f3ce38aafff08155e49bc9fb58d54 100644 (file)
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "9f3035a68ea28a4f87fd5c8433bb5464",
+    "content-hash": "f50d72e239361fb418ad79f7e7ff4a7c",
     "packages": [
     "packages": [
-        {
-            "name": "beyondcode/laravel-websockets",
-            "version": "1.14.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/beyondcode/laravel-websockets.git",
-                "reference": "fee9a81e42a096d2aaca216ce91acf6e25d8c06d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/beyondcode/laravel-websockets/zipball/fee9a81e42a096d2aaca216ce91acf6e25d8c06d",
-                "reference": "fee9a81e42a096d2aaca216ce91acf6e25d8c06d",
-                "shasum": ""
-            },
-            "require": {
-                "cboden/ratchet": "^0.4.1",
-                "ext-json": "*",
-                "facade/ignition-contracts": "^1.0",
-                "guzzlehttp/psr7": "^1.7|^2.0",
-                "illuminate/broadcasting": "^6.0|^7.0|^8.0|^9.0|^10.0",
-                "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0",
-                "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0",
-                "illuminate/routing": "^6.0|^7.0|^8.0|^9.0|^10.0",
-                "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0",
-                "php": "^7.2|^8.0",
-                "pusher/pusher-php-server": "^3.0|^4.0|^5.0|^6.0|^7.0",
-                "react/dns": "^1.1",
-                "react/http": "^1.1",
-                "symfony/http-kernel": "^4.0|^5.0|^6.0",
-                "symfony/psr-http-message-bridge": "^1.1|^2.0"
-            },
-            "require-dev": {
-                "mockery/mockery": "^1.3.3",
-                "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0",
-                "phpunit/phpunit": "^8.0|^9.0|^10.0"
-            },
-            "type": "library",
-            "extra": {
-                "laravel": {
-                    "providers": [
-                        "BeyondCode\\LaravelWebSockets\\WebSocketsServiceProvider"
-                    ],
-                    "aliases": {
-                        "WebSocketRouter": "BeyondCode\\LaravelWebSockets\\Facades\\WebSocketRouter"
-                    }
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "BeyondCode\\LaravelWebSockets\\": "src"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Marcel Pociot",
-                    "email": "marcel@beyondco.de",
-                    "homepage": "https://beyondcode.de",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Freek Van der Herten",
-                    "email": "freek@spatie.be",
-                    "homepage": "https://spatie.be",
-                    "role": "Developer"
-                }
-            ],
-            "description": "An easy to use WebSocket server",
-            "homepage": "https://github.com/beyondcode/laravel-websockets",
-            "keywords": [
-                "beyondcode",
-                "laravel-websockets"
-            ],
-            "support": {
-                "issues": "https://github.com/beyondcode/laravel-websockets/issues",
-                "source": "https://github.com/beyondcode/laravel-websockets/tree/1.14.1"
-            },
-            "abandoned": true,
-            "time": "2023-08-30T07:23:12+00:00"
-        },
         {
             "name": "brick/math",
         {
             "name": "brick/math",
-            "version": "0.11.0",
+            "version": "0.12.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/brick/math.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/brick/math.git",
-                "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478"
+                "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/brick/math/zipball/0ad82ce168c82ba30d1c01ec86116ab52f589478",
-                "reference": "0ad82ce168c82ba30d1c01ec86116ab52f589478",
+                "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
+                "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": "^8.0"
+                "php": "^8.1"
             },
             "require-dev": {
                 "php-coveralls/php-coveralls": "^2.2",
             },
             "require-dev": {
                 "php-coveralls/php-coveralls": "^2.2",
-                "phpunit/phpunit": "^9.0",
-                "vimeo/psalm": "5.0.0"
+                "phpunit/phpunit": "^10.1",
+                "vimeo/psalm": "6.8.8"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
                 "arithmetic",
                 "bigdecimal",
                 "bignum",
                 "arithmetic",
                 "bigdecimal",
                 "bignum",
+                "bignumber",
                 "brick",
                 "brick",
-                "math"
+                "decimal",
+                "integer",
+                "math",
+                "mathematics",
+                "rational"
             ],
             "support": {
                 "issues": "https://github.com/brick/math/issues",
             ],
             "support": {
                 "issues": "https://github.com/brick/math/issues",
-                "source": "https://github.com/brick/math/tree/0.11.0"
+                "source": "https://github.com/brick/math/tree/0.12.3"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-01-15T23:15:59+00:00"
+            "time": "2025-02-28T13:11:00+00:00"
         },
         {
             "name": "carbonphp/carbon-doctrine-types",
         },
         {
             "name": "carbonphp/carbon-doctrine-types",
-            "version": "2.1.0",
+            "version": "3.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/CarbonPHP/carbon-doctrine-types.git",
-                "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb"
+                "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/99f76ffa36cce3b70a4a6abce41dba15ca2e84cb",
-                "reference": "99f76ffa36cce3b70a4a6abce41dba15ca2e84cb",
+                "url": "https://api.github.com/repos/CarbonPHP/carbon-doctrine-types/zipball/18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
+                "reference": "18ba5ddfec8976260ead6e866180bd5d2f71aa1d",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": "^7.4 || ^8.0"
+                "php": "^8.1"
             },
             "conflict": {
             },
             "conflict": {
-                "doctrine/dbal": "<3.7.0 || >=4.0.0"
+                "doctrine/dbal": "<4.0.0 || >=5.0.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "doctrine/dbal": "^3.7.0",
+                "doctrine/dbal": "^4.0.0",
                 "nesbot/carbon": "^2.71.0 || ^3.0.0",
                 "phpunit/phpunit": "^10.3"
             },
                 "nesbot/carbon": "^2.71.0 || ^3.0.0",
                 "phpunit/phpunit": "^10.3"
             },
             ],
             "support": {
                 "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
             ],
             "support": {
                 "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues",
-                "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/2.1.0"
+                "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-11T17:09:12+00:00"
+            "time": "2024-02-09T16:56:22+00:00"
         },
         {
         },
         {
-            "name": "cboden/ratchet",
-            "version": "v0.4.4",
+            "name": "clue/redis-protocol",
+            "version": "v0.3.2",
             "source": {
                 "type": "git",
             "source": {
                 "type": "git",
-                "url": "https://github.com/ratchetphp/Ratchet.git",
-                "reference": "5012dc954541b40c5599d286fd40653f5716a38f"
+                "url": "https://github.com/clue/redis-protocol.git",
+                "reference": "6f565332f5531b7722d1e9c445314b91862f6d6c"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ratchetphp/Ratchet/zipball/5012dc954541b40c5599d286fd40653f5716a38f",
-                "reference": "5012dc954541b40c5599d286fd40653f5716a38f",
+                "url": "https://api.github.com/repos/clue/redis-protocol/zipball/6f565332f5531b7722d1e9c445314b91862f6d6c",
+                "reference": "6f565332f5531b7722d1e9c445314b91862f6d6c",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/psr7": "^1.7|^2.0",
-                "php": ">=5.4.2",
-                "ratchet/rfc6455": "^0.3.1",
-                "react/event-loop": ">=0.4",
-                "react/socket": "^1.0 || ^0.8 || ^0.7 || ^0.6 || ^0.5",
-                "symfony/http-foundation": "^2.6|^3.0|^4.0|^5.0|^6.0",
-                "symfony/routing": "^2.6|^3.0|^4.0|^5.0|^6.0"
+                "php": ">=5.3"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "~4.8"
+                "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
-                    "Ratchet\\": "src/Ratchet"
+                    "Clue\\Redis\\Protocol\\": "src/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
             ],
             "authors": [
                 {
             ],
             "authors": [
                 {
-                    "name": "Chris Boden",
-                    "email": "cboden@gmail.com",
-                    "role": "Developer"
+                    "name": "Christian Lück",
+                    "email": "christian@lueck.tv"
+                }
+            ],
+            "description": "A streaming Redis protocol (RESP) parser and serializer written in pure PHP.",
+            "homepage": "https://github.com/clue/redis-protocol",
+            "keywords": [
+                "parser",
+                "protocol",
+                "redis",
+                "resp",
+                "serializer",
+                "streaming"
+            ],
+            "support": {
+                "issues": "https://github.com/clue/redis-protocol/issues",
+                "source": "https://github.com/clue/redis-protocol/tree/v0.3.2"
+            },
+            "funding": [
+                {
+                    "url": "https://clue.engineering/support",
+                    "type": "custom"
                 },
                 {
                 },
                 {
-                    "name": "Matt Bonneau",
-                    "role": "Developer"
+                    "url": "https://github.com/clue",
+                    "type": "github"
                 }
             ],
                 }
             ],
-            "description": "PHP WebSocket library",
-            "homepage": "http://socketo.me",
+            "time": "2024-08-07T11:06:28+00:00"
+        },
+        {
+            "name": "clue/redis-react",
+            "version": "v2.8.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/clue/reactphp-redis.git",
+                "reference": "84569198dfd5564977d2ae6a32de4beb5a24bdca"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/clue/reactphp-redis/zipball/84569198dfd5564977d2ae6a32de4beb5a24bdca",
+                "reference": "84569198dfd5564977d2ae6a32de4beb5a24bdca",
+                "shasum": ""
+            },
+            "require": {
+                "clue/redis-protocol": "^0.3.2",
+                "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
+                "php": ">=5.3",
+                "react/event-loop": "^1.2",
+                "react/promise": "^3.2 || ^2.0 || ^1.1",
+                "react/promise-timer": "^1.11",
+                "react/socket": "^1.16"
+            },
+            "require-dev": {
+                "clue/block-react": "^1.5",
+                "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Clue\\React\\Redis\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Christian Lück",
+                    "email": "christian@clue.engineering"
+                }
+            ],
+            "description": "Async Redis client implementation, built on top of ReactPHP.",
+            "homepage": "https://github.com/clue/reactphp-redis",
             "keywords": [
             "keywords": [
-                "Ratchet",
-                "WebSockets",
-                "server",
-                "sockets",
-                "websocket"
+                "async",
+                "client",
+                "database",
+                "reactphp",
+                "redis"
             ],
             "support": {
             ],
             "support": {
-                "chat": "https://gitter.im/reactphp/reactphp",
-                "issues": "https://github.com/ratchetphp/Ratchet/issues",
-                "source": "https://github.com/ratchetphp/Ratchet/tree/v0.4.4"
+                "issues": "https://github.com/clue/reactphp-redis/issues",
+                "source": "https://github.com/clue/reactphp-redis/tree/v2.8.0"
             },
             },
-            "time": "2021-12-14T00:20:41+00:00"
+            "funding": [
+                {
+                    "url": "https://clue.engineering/support",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/clue",
+                    "type": "github"
+                }
+            ],
+            "time": "2025-01-03T16:18:33+00:00"
         },
         {
             "name": "dflydev/dot-access-data",
         },
         {
             "name": "dflydev/dot-access-data",
-            "version": "v3.0.2",
+            "version": "v3.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/dflydev/dflydev-dot-access-data.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/dflydev/dflydev-dot-access-data.git",
-                "reference": "f41715465d65213d644d3141a6a93081be5d3549"
+                "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/f41715465d65213d644d3141a6a93081be5d3549",
-                "reference": "f41715465d65213d644d3141a6a93081be5d3549",
+                "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f",
+                "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues",
             ],
             "support": {
                 "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues",
-                "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.2"
+                "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3"
             },
             },
-            "time": "2022-10-27T11:44:00+00:00"
+            "time": "2024-07-08T12:26:09+00:00"
         },
         {
             "name": "discord-php/http",
         },
         {
             "name": "discord-php/http",
                 "simplito/elliptic-php": "^1.0"
             },
             "suggest": {
                 "simplito/elliptic-php": "^1.0"
             },
             "suggest": {
-                "simplito/elliptic-php": "Required to validate interaction signatures."
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Discord\\": "discord"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Ian Webster",
-                    "email": "ianw_php@ianww.com"
-                }
-            ],
-            "description": "Utils for implementing the Discord Interactions API",
-            "keywords": [
-                "discord"
-            ],
-            "support": {
-                "issues": "https://github.com/discord/discord-interactions-php/issues",
-                "source": "https://github.com/discord/discord-interactions-php/tree/2.2.0"
-            },
-            "time": "2022-02-09T17:58:51+00:00"
-        },
-        {
-            "name": "doctrine/cache",
-            "version": "2.2.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/cache.git",
-                "reference": "1ca8f21980e770095a31456042471a57bc4c68fb"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb",
-                "reference": "1ca8f21980e770095a31456042471a57bc4c68fb",
-                "shasum": ""
-            },
-            "require": {
-                "php": "~7.1 || ^8.0"
-            },
-            "conflict": {
-                "doctrine/common": ">2.2,<2.4"
-            },
-            "require-dev": {
-                "cache/integration-tests": "dev-master",
-                "doctrine/coding-standard": "^9",
-                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
-                "psr/cache": "^1.0 || ^2.0 || ^3.0",
-                "symfony/cache": "^4.4 || ^5.4 || ^6",
-                "symfony/var-exporter": "^4.4 || ^5.4 || ^6"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Guilherme Blanco",
-                    "email": "guilhermeblanco@gmail.com"
-                },
-                {
-                    "name": "Roman Borschel",
-                    "email": "roman@code-factory.org"
-                },
-                {
-                    "name": "Benjamin Eberlei",
-                    "email": "kontakt@beberlei.de"
-                },
-                {
-                    "name": "Jonathan Wage",
-                    "email": "jonwage@gmail.com"
-                },
-                {
-                    "name": "Johannes Schmitt",
-                    "email": "schmittjoh@gmail.com"
-                }
-            ],
-            "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
-            "homepage": "https://www.doctrine-project.org/projects/cache.html",
-            "keywords": [
-                "abstraction",
-                "apcu",
-                "cache",
-                "caching",
-                "couchdb",
-                "memcached",
-                "php",
-                "redis",
-                "xcache"
-            ],
-            "support": {
-                "issues": "https://github.com/doctrine/cache/issues",
-                "source": "https://github.com/doctrine/cache/tree/2.2.0"
-            },
-            "funding": [
-                {
-                    "url": "https://www.doctrine-project.org/sponsorship.html",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://www.patreon.com/phpdoctrine",
-                    "type": "patreon"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2022-05-20T20:07:39+00:00"
-        },
-        {
-            "name": "doctrine/dbal",
-            "version": "3.8.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/dbal.git",
-                "reference": "db922ba9436b7b18a23d1653a0b41ff2369ca41c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/dbal/zipball/db922ba9436b7b18a23d1653a0b41ff2369ca41c",
-                "reference": "db922ba9436b7b18a23d1653a0b41ff2369ca41c",
-                "shasum": ""
-            },
-            "require": {
-                "composer-runtime-api": "^2",
-                "doctrine/cache": "^1.11|^2.0",
-                "doctrine/deprecations": "^0.5.3|^1",
-                "doctrine/event-manager": "^1|^2",
-                "php": "^7.4 || ^8.0",
-                "psr/cache": "^1|^2|^3",
-                "psr/log": "^1|^2|^3"
-            },
-            "require-dev": {
-                "doctrine/coding-standard": "12.0.0",
-                "fig/log-test": "^1",
-                "jetbrains/phpstorm-stubs": "2023.1",
-                "phpstan/phpstan": "1.10.58",
-                "phpstan/phpstan-strict-rules": "^1.5",
-                "phpunit/phpunit": "9.6.16",
-                "psalm/plugin-phpunit": "0.18.4",
-                "slevomat/coding-standard": "8.13.1",
-                "squizlabs/php_codesniffer": "3.9.0",
-                "symfony/cache": "^5.4|^6.0|^7.0",
-                "symfony/console": "^4.4|^5.4|^6.0|^7.0",
-                "vimeo/psalm": "4.30.0"
-            },
-            "suggest": {
-                "symfony/console": "For helpful console commands such as SQL execution and import of files."
-            },
-            "bin": [
-                "bin/doctrine-dbal"
-            ],
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\DBAL\\": "src"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Guilherme Blanco",
-                    "email": "guilhermeblanco@gmail.com"
-                },
-                {
-                    "name": "Roman Borschel",
-                    "email": "roman@code-factory.org"
-                },
-                {
-                    "name": "Benjamin Eberlei",
-                    "email": "kontakt@beberlei.de"
-                },
-                {
-                    "name": "Jonathan Wage",
-                    "email": "jonwage@gmail.com"
-                }
-            ],
-            "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
-            "homepage": "https://www.doctrine-project.org/projects/dbal.html",
-            "keywords": [
-                "abstraction",
-                "database",
-                "db2",
-                "dbal",
-                "mariadb",
-                "mssql",
-                "mysql",
-                "oci8",
-                "oracle",
-                "pdo",
-                "pgsql",
-                "postgresql",
-                "queryobject",
-                "sasql",
-                "sql",
-                "sqlite",
-                "sqlserver",
-                "sqlsrv"
-            ],
-            "support": {
-                "issues": "https://github.com/doctrine/dbal/issues",
-                "source": "https://github.com/doctrine/dbal/tree/3.8.3"
-            },
-            "funding": [
-                {
-                    "url": "https://www.doctrine-project.org/sponsorship.html",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://www.patreon.com/phpdoctrine",
-                    "type": "patreon"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2024-03-03T15:55:06+00:00"
-        },
-        {
-            "name": "doctrine/deprecations",
-            "version": "1.1.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/deprecations.git",
-                "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
-                "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1 || ^8.0"
-            },
-            "require-dev": {
-                "doctrine/coding-standard": "^9",
-                "phpstan/phpstan": "1.4.10 || 1.10.15",
-                "phpstan/phpstan-phpunit": "^1.0",
-                "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
-                "psalm/plugin-phpunit": "0.18.4",
-                "psr/log": "^1 || ^2 || ^3",
-                "vimeo/psalm": "4.30.0 || 5.12.0"
-            },
-            "suggest": {
-                "psr/log": "Allows logging deprecations via PSR-3 logger implementation"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
-            "homepage": "https://www.doctrine-project.org/",
-            "support": {
-                "issues": "https://github.com/doctrine/deprecations/issues",
-                "source": "https://github.com/doctrine/deprecations/tree/1.1.3"
-            },
-            "time": "2024-01-30T19:34:25+00:00"
-        },
-        {
-            "name": "doctrine/event-manager",
-            "version": "2.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/event-manager.git",
-                "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32",
-                "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^8.1"
-            },
-            "conflict": {
-                "doctrine/common": "<2.9"
-            },
-            "require-dev": {
-                "doctrine/coding-standard": "^10",
-                "phpstan/phpstan": "^1.8.8",
-                "phpunit/phpunit": "^9.5",
-                "vimeo/psalm": "^4.28"
+                "simplito/elliptic-php": "Required to validate interaction signatures."
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
-                    "Doctrine\\Common\\": "src"
+                    "Discord\\": "discord"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
             ],
             "authors": [
                 {
             ],
             "authors": [
                 {
-                    "name": "Guilherme Blanco",
-                    "email": "guilhermeblanco@gmail.com"
-                },
-                {
-                    "name": "Roman Borschel",
-                    "email": "roman@code-factory.org"
-                },
-                {
-                    "name": "Benjamin Eberlei",
-                    "email": "kontakt@beberlei.de"
-                },
-                {
-                    "name": "Jonathan Wage",
-                    "email": "jonwage@gmail.com"
-                },
-                {
-                    "name": "Johannes Schmitt",
-                    "email": "schmittjoh@gmail.com"
-                },
-                {
-                    "name": "Marco Pivetta",
-                    "email": "ocramius@gmail.com"
+                    "name": "Ian Webster",
+                    "email": "ianw_php@ianww.com"
                 }
             ],
                 }
             ],
-            "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
-            "homepage": "https://www.doctrine-project.org/projects/event-manager.html",
+            "description": "Utils for implementing the Discord Interactions API",
             "keywords": [
             "keywords": [
-                "event",
-                "event dispatcher",
-                "event manager",
-                "event system",
-                "events"
+                "discord"
             ],
             "support": {
             ],
             "support": {
-                "issues": "https://github.com/doctrine/event-manager/issues",
-                "source": "https://github.com/doctrine/event-manager/tree/2.0.0"
+                "issues": "https://github.com/discord/discord-interactions-php/issues",
+                "source": "https://github.com/discord/discord-interactions-php/tree/2.2.0"
             },
             },
-            "funding": [
-                {
-                    "url": "https://www.doctrine-project.org/sponsorship.html",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://www.patreon.com/phpdoctrine",
-                    "type": "patreon"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2022-10-12T20:59:15+00:00"
+            "time": "2022-02-09T17:58:51+00:00"
         },
         {
             "name": "doctrine/inflector",
         },
         {
             "name": "doctrine/inflector",
         },
         {
             "name": "dragonmantank/cron-expression",
         },
         {
             "name": "dragonmantank/cron-expression",
-            "version": "v3.3.3",
+            "version": "v3.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/dragonmantank/cron-expression.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/dragonmantank/cron-expression.git",
-                "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a"
+                "reference": "8c784d071debd117328803d86b2097615b457500"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
-                "reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
+                "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500",
+                "reference": "8c784d071debd117328803d86b2097615b457500",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             "require-dev": {
                 "phpstan/extension-installer": "^1.0",
                 "phpstan/phpstan": "^1.0",
             "require-dev": {
                 "phpstan/extension-installer": "^1.0",
                 "phpstan/phpstan": "^1.0",
-                "phpstan/phpstan-webmozart-assert": "^1.0",
                 "phpunit/phpunit": "^7.0|^8.0|^9.0"
             },
             "type": "library",
                 "phpunit/phpunit": "^7.0|^8.0|^9.0"
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.x-dev"
+                }
+            },
             "autoload": {
                 "psr-4": {
                     "Cron\\": "src/Cron/"
             "autoload": {
                 "psr-4": {
                     "Cron\\": "src/Cron/"
             ],
             "support": {
                 "issues": "https://github.com/dragonmantank/cron-expression/issues",
             ],
             "support": {
                 "issues": "https://github.com/dragonmantank/cron-expression/issues",
-                "source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3"
+                "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-08-10T19:36:49+00:00"
+            "time": "2024-10-09T13:47:03+00:00"
         },
         {
             "name": "egulias/email-validator",
         },
         {
             "name": "egulias/email-validator",
-            "version": "4.0.2",
+            "version": "4.0.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/egulias/EmailValidator.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/egulias/EmailValidator.git",
-                "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e"
+                "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e",
-                "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e",
+                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa",
+                "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/egulias/EmailValidator/issues",
             ],
             "support": {
                 "issues": "https://github.com/egulias/EmailValidator/issues",
-                "source": "https://github.com/egulias/EmailValidator/tree/4.0.2"
+                "source": "https://github.com/egulias/EmailValidator/tree/4.0.4"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-10-06T06:47:41+00:00"
+            "time": "2025-03-06T22:45:56+00:00"
         },
         {
             "name": "evenement/evenement",
         },
         {
             "name": "evenement/evenement",
             },
             "time": "2023-08-08T05:53:35+00:00"
         },
             },
             "time": "2023-08-08T05:53:35+00:00"
         },
-        {
-            "name": "facade/ignition-contracts",
-            "version": "1.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/facade/ignition-contracts.git",
-                "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267",
-                "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.3|^8.0"
-            },
-            "require-dev": {
-                "friendsofphp/php-cs-fixer": "^v2.15.8",
-                "phpunit/phpunit": "^9.3.11",
-                "vimeo/psalm": "^3.17.1"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Facade\\IgnitionContracts\\": "src"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Freek Van der Herten",
-                    "email": "freek@spatie.be",
-                    "homepage": "https://flareapp.io",
-                    "role": "Developer"
-                }
-            ],
-            "description": "Solution contracts for Ignition",
-            "homepage": "https://github.com/facade/ignition-contracts",
-            "keywords": [
-                "contracts",
-                "flare",
-                "ignition"
-            ],
-            "support": {
-                "issues": "https://github.com/facade/ignition-contracts/issues",
-                "source": "https://github.com/facade/ignition-contracts/tree/1.0.2"
-            },
-            "time": "2020-10-16T08:27:54+00:00"
-        },
         {
             "name": "fig/http-message-util",
             "version": "1.1.5",
         {
             "name": "fig/http-message-util",
             "version": "1.1.5",
         },
         {
             "name": "graham-campbell/result-type",
         },
         {
             "name": "graham-campbell/result-type",
-            "version": "v1.1.2",
+            "version": "v1.1.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/GrahamCampbell/Result-Type.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/GrahamCampbell/Result-Type.git",
-                "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862"
+                "reference": "3ba905c11371512af9d9bdd27d99b782216b6945"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/fbd48bce38f73f8a4ec8583362e732e4095e5862",
-                "reference": "fbd48bce38f73f8a4ec8583362e732e4095e5862",
+                "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945",
+                "reference": "3ba905c11371512af9d9bdd27d99b782216b6945",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.2.5 || ^8.0",
                 "shasum": ""
             },
             "require": {
                 "php": "^7.2.5 || ^8.0",
-                "phpoption/phpoption": "^1.9.2"
+                "phpoption/phpoption": "^1.9.3"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/GrahamCampbell/Result-Type/issues",
             ],
             "support": {
                 "issues": "https://github.com/GrahamCampbell/Result-Type/issues",
-                "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.2"
+                "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-11-12T22:16:48+00:00"
+            "time": "2024-07-20T21:45:45+00:00"
         },
         {
             "name": "guzzlehttp/guzzle",
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "7.8.1",
+            "version": "7.9.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
+                "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
-                "reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
+                "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
-                "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
+                "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
+                "guzzlehttp/psr7": "^2.7.0",
                 "php": "^7.2.5 || ^8.0",
                 "psr/http-client": "^1.0",
                 "symfony/deprecation-contracts": "^2.2 || ^3.0"
                 "php": "^7.2.5 || ^8.0",
                 "psr/http-client": "^1.0",
                 "symfony/deprecation-contracts": "^2.2 || ^3.0"
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
                 "ext-curl": "*",
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
                 "ext-curl": "*",
-                "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+                "guzzle/client-integration-tests": "3.0.2",
                 "php-http/message-factory": "^1.1",
                 "php-http/message-factory": "^1.1",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20",
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
             },
             "suggest": {
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
             },
             "suggest": {
             ],
             "support": {
                 "issues": "https://github.com/guzzle/guzzle/issues",
             ],
             "support": {
                 "issues": "https://github.com/guzzle/guzzle/issues",
-                "source": "https://github.com/guzzle/guzzle/tree/7.8.1"
+                "source": "https://github.com/guzzle/guzzle/tree/7.9.3"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-03T20:35:24+00:00"
+            "time": "2025-03-27T13:37:11+00:00"
         },
         {
             "name": "guzzlehttp/promises",
         },
         {
             "name": "guzzlehttp/promises",
-            "version": "2.0.2",
+            "version": "2.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/promises.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/promises.git",
-                "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
+                "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
-                "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c",
+                "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
             ],
             "support": {
                 "issues": "https://github.com/guzzle/promises/issues",
             ],
             "support": {
                 "issues": "https://github.com/guzzle/promises/issues",
-                "source": "https://github.com/guzzle/promises/tree/2.0.2"
+                "source": "https://github.com/guzzle/promises/tree/2.2.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-03T20:19:20+00:00"
+            "time": "2025-03-27T13:27:01+00:00"
         },
         {
             "name": "guzzlehttp/psr7",
         },
         {
             "name": "guzzlehttp/psr7",
-            "version": "2.6.2",
+            "version": "2.7.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/psr7.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/psr7.git",
-                "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
+                "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
-                "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16",
+                "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
-                "http-interop/http-factory-tests": "^0.9",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+                "http-interop/http-factory-tests": "0.9.0",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20"
             },
             "suggest": {
                 "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
             },
             "suggest": {
                 "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
             ],
             "support": {
                 "issues": "https://github.com/guzzle/psr7/issues",
             ],
             "support": {
                 "issues": "https://github.com/guzzle/psr7/issues",
-                "source": "https://github.com/guzzle/psr7/tree/2.6.2"
+                "source": "https://github.com/guzzle/psr7/tree/2.7.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-03T20:05:35+00:00"
+            "time": "2025-03-27T12:30:47+00:00"
         },
         {
             "name": "guzzlehttp/uri-template",
         },
         {
             "name": "guzzlehttp/uri-template",
-            "version": "v1.0.3",
+            "version": "v1.0.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/uri-template.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/uri-template.git",
-                "reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c"
+                "reference": "30e286560c137526eccd4ce21b2de477ab0676d2"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/uri-template/zipball/ecea8feef63bd4fef1f037ecb288386999ecc11c",
-                "reference": "ecea8feef63bd4fef1f037ecb288386999ecc11c",
+                "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2",
+                "reference": "30e286560c137526eccd4ce21b2de477ab0676d2",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/guzzle/uri-template/issues",
             ],
             "support": {
                 "issues": "https://github.com/guzzle/uri-template/issues",
-                "source": "https://github.com/guzzle/uri-template/tree/v1.0.3"
+                "source": "https://github.com/guzzle/uri-template/tree/v1.0.4"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-03T19:50:20+00:00"
+            "time": "2025-02-03T10:55:03+00:00"
         },
         {
             "name": "jakyeru/larascord",
         },
         {
             "name": "jakyeru/larascord",
-            "version": "v3.2.0",
+            "version": "v6.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/JakyeRU/Larascord.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/JakyeRU/Larascord.git",
-                "reference": "1ad8ac83e973b4b646ecdc78dcf94930131bada3"
+                "reference": "d1099d1418022eda970fec4f13634ee5fbee93b3"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/JakyeRU/Larascord/zipball/1ad8ac83e973b4b646ecdc78dcf94930131bada3",
-                "reference": "1ad8ac83e973b4b646ecdc78dcf94930131bada3",
+                "url": "https://api.github.com/repos/JakyeRU/Larascord/zipball/d1099d1418022eda970fec4f13634ee5fbee93b3",
+                "reference": "d1099d1418022eda970fec4f13634ee5fbee93b3",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/guzzle": "^7.4"
+                "guzzlehttp/guzzle": "^7.5",
+                "laravel/breeze": "^v2.0",
+                "laravel/framework": "^11",
+                "php": "^8.2|^8.3"
             },
             "require-dev": {
             },
             "require-dev": {
-                "orchestra/testbench": "^6.22"
+                "orchestra/testbench": "^9"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
             "description": "Larascord is a package that allows you to authenticate users in your Laravel application using Discord.",
             "support": {
                 "issues": "https://github.com/JakyeRU/Larascord/issues",
             "description": "Larascord is a package that allows you to authenticate users in your Laravel application using Discord.",
             "support": {
                 "issues": "https://github.com/JakyeRU/Larascord/issues",
-                "source": "https://github.com/JakyeRU/Larascord/tree/v3.2.0"
+                "source": "https://github.com/JakyeRU/Larascord/tree/v6.0.3"
             },
             },
-            "time": "2022-06-26T11:09:59+00:00"
+            "time": "2025-06-18T18:41:42+00:00"
         },
         {
             "name": "laravel/breeze",
         },
         {
             "name": "laravel/breeze",
-            "version": "v1.29.1",
+            "version": "v2.3.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/breeze.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/breeze.git",
-                "reference": "22c53b84b7fff91b01a318d71a10dfc251e92849"
+                "reference": "73149b5d84be3881b2fdda94b2ad289e7905c1a4"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/breeze/zipball/22c53b84b7fff91b01a318d71a10dfc251e92849",
-                "reference": "22c53b84b7fff91b01a318d71a10dfc251e92849",
+                "url": "https://api.github.com/repos/laravel/breeze/zipball/73149b5d84be3881b2fdda94b2ad289e7905c1a4",
+                "reference": "73149b5d84be3881b2fdda94b2ad289e7905c1a4",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "illuminate/console": "^10.17",
-                "illuminate/filesystem": "^10.17",
-                "illuminate/support": "^10.17",
-                "illuminate/validation": "^10.17",
-                "php": "^8.1.0"
+                "illuminate/console": "^11.0|^12.0",
+                "illuminate/filesystem": "^11.0|^12.0",
+                "illuminate/support": "^11.0|^12.0",
+                "illuminate/validation": "^11.0|^12.0",
+                "php": "^8.2.0",
+                "symfony/console": "^7.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "orchestra/testbench": "^8.0",
-                "phpstan/phpstan": "^1.10"
+                "laravel/framework": "^11.0|^12.0",
+                "orchestra/testbench-core": "^9.0|^10.0",
+                "phpstan/phpstan": "^2.0"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-master": "1.x-dev"
-                },
                 "laravel": {
                     "providers": [
                         "Laravel\\Breeze\\BreezeServiceProvider"
                 "laravel": {
                     "providers": [
                         "Laravel\\Breeze\\BreezeServiceProvider"
                 "issues": "https://github.com/laravel/breeze/issues",
                 "source": "https://github.com/laravel/breeze"
             },
                 "issues": "https://github.com/laravel/breeze/issues",
                 "source": "https://github.com/laravel/breeze"
             },
-            "time": "2024-03-04T14:35:21+00:00"
+            "time": "2025-06-17T13:07:20+00:00"
         },
         {
             "name": "laravel/framework",
         },
         {
             "name": "laravel/framework",
-            "version": "v10.48.4",
+            "version": "v11.45.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
-                "reference": "7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72"
+                "reference": "b09ba32795b8e71df10856a2694706663984a239"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/framework/zipball/7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72",
-                "reference": "7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/b09ba32795b8e71df10856a2694706663984a239",
+                "reference": "b09ba32795b8e71df10856a2694706663984a239",
                 "shasum": ""
             },
             "require": {
                 "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12",
                 "composer-runtime-api": "^2.2",
                 "doctrine/inflector": "^2.0.5",
                 "shasum": ""
             },
             "require": {
                 "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12",
                 "composer-runtime-api": "^2.2",
                 "doctrine/inflector": "^2.0.5",
-                "dragonmantank/cron-expression": "^3.3.2",
+                "dragonmantank/cron-expression": "^3.4",
                 "egulias/email-validator": "^3.2.1|^4.0",
                 "ext-ctype": "*",
                 "ext-filter": "*",
                 "egulias/email-validator": "^3.2.1|^4.0",
                 "ext-ctype": "*",
                 "ext-filter": "*",
                 "ext-openssl": "*",
                 "ext-session": "*",
                 "ext-tokenizer": "*",
                 "ext-openssl": "*",
                 "ext-session": "*",
                 "ext-tokenizer": "*",
-                "fruitcake/php-cors": "^1.2",
+                "fruitcake/php-cors": "^1.3",
+                "guzzlehttp/guzzle": "^7.8.2",
                 "guzzlehttp/uri-template": "^1.0",
                 "guzzlehttp/uri-template": "^1.0",
-                "laravel/prompts": "^0.1.9",
-                "laravel/serializable-closure": "^1.3",
-                "league/commonmark": "^2.2.1",
-                "league/flysystem": "^3.8.0",
+                "laravel/prompts": "^0.1.18|^0.2.0|^0.3.0",
+                "laravel/serializable-closure": "^1.3|^2.0",
+                "league/commonmark": "^2.7",
+                "league/flysystem": "^3.25.1",
+                "league/flysystem-local": "^3.25.1",
+                "league/uri": "^7.5.1",
                 "monolog/monolog": "^3.0",
                 "monolog/monolog": "^3.0",
-                "nesbot/carbon": "^2.67",
-                "nunomaduro/termwind": "^1.13",
-                "php": "^8.1",
+                "nesbot/carbon": "^2.72.6|^3.8.4",
+                "nunomaduro/termwind": "^2.0",
+                "php": "^8.2",
                 "psr/container": "^1.1.1|^2.0.1",
                 "psr/log": "^1.0|^2.0|^3.0",
                 "psr/simple-cache": "^1.0|^2.0|^3.0",
                 "ramsey/uuid": "^4.7",
                 "psr/container": "^1.1.1|^2.0.1",
                 "psr/log": "^1.0|^2.0|^3.0",
                 "psr/simple-cache": "^1.0|^2.0|^3.0",
                 "ramsey/uuid": "^4.7",
-                "symfony/console": "^6.2",
-                "symfony/error-handler": "^6.2",
-                "symfony/finder": "^6.2",
-                "symfony/http-foundation": "^6.4",
-                "symfony/http-kernel": "^6.2",
-                "symfony/mailer": "^6.2",
-                "symfony/mime": "^6.2",
-                "symfony/process": "^6.2",
-                "symfony/routing": "^6.2",
-                "symfony/uid": "^6.2",
-                "symfony/var-dumper": "^6.2",
+                "symfony/console": "^7.0.3",
+                "symfony/error-handler": "^7.0.3",
+                "symfony/finder": "^7.0.3",
+                "symfony/http-foundation": "^7.2.0",
+                "symfony/http-kernel": "^7.0.3",
+                "symfony/mailer": "^7.0.3",
+                "symfony/mime": "^7.0.3",
+                "symfony/polyfill-php83": "^1.31",
+                "symfony/process": "^7.0.3",
+                "symfony/routing": "^7.0.3",
+                "symfony/uid": "^7.0.3",
+                "symfony/var-dumper": "^7.0.3",
                 "tijsverkoyen/css-to-inline-styles": "^2.2.5",
                 "tijsverkoyen/css-to-inline-styles": "^2.2.5",
-                "vlucas/phpdotenv": "^5.4.1",
-                "voku/portable-ascii": "^2.0"
+                "vlucas/phpdotenv": "^5.6.1",
+                "voku/portable-ascii": "^2.0.2"
             },
             "conflict": {
             },
             "conflict": {
-                "carbonphp/carbon-doctrine-types": ">=3.0",
-                "doctrine/dbal": ">=4.0",
-                "mockery/mockery": "1.6.8",
-                "phpunit/phpunit": ">=11.0.0",
                 "tightenco/collect": "<5.5.33"
             },
             "provide": {
                 "psr/container-implementation": "1.1|2.0",
                 "tightenco/collect": "<5.5.33"
             },
             "provide": {
                 "psr/container-implementation": "1.1|2.0",
+                "psr/log-implementation": "1.0|2.0|3.0",
                 "psr/simple-cache-implementation": "1.0|2.0|3.0"
             },
             "replace": {
                 "psr/simple-cache-implementation": "1.0|2.0|3.0"
             },
             "replace": {
                 "illuminate/bus": "self.version",
                 "illuminate/cache": "self.version",
                 "illuminate/collections": "self.version",
                 "illuminate/bus": "self.version",
                 "illuminate/cache": "self.version",
                 "illuminate/collections": "self.version",
+                "illuminate/concurrency": "self.version",
                 "illuminate/conditionable": "self.version",
                 "illuminate/config": "self.version",
                 "illuminate/console": "self.version",
                 "illuminate/conditionable": "self.version",
                 "illuminate/config": "self.version",
                 "illuminate/console": "self.version",
                 "illuminate/testing": "self.version",
                 "illuminate/translation": "self.version",
                 "illuminate/validation": "self.version",
                 "illuminate/testing": "self.version",
                 "illuminate/translation": "self.version",
                 "illuminate/validation": "self.version",
-                "illuminate/view": "self.version"
+                "illuminate/view": "self.version",
+                "spatie/once": "*"
             },
             "require-dev": {
                 "ably/ably-php": "^1.0",
             },
             "require-dev": {
                 "ably/ably-php": "^1.0",
-                "aws/aws-sdk-php": "^3.235.5",
-                "doctrine/dbal": "^3.5.1",
+                "aws/aws-sdk-php": "^3.322.9",
                 "ext-gmp": "*",
                 "ext-gmp": "*",
-                "fakerphp/faker": "^1.21",
-                "guzzlehttp/guzzle": "^7.5",
-                "league/flysystem-aws-s3-v3": "^3.0",
-                "league/flysystem-ftp": "^3.0",
-                "league/flysystem-path-prefixing": "^3.3",
-                "league/flysystem-read-only": "^3.3",
-                "league/flysystem-sftp-v3": "^3.0",
-                "mockery/mockery": "^1.5.1",
-                "nyholm/psr7": "^1.2",
-                "orchestra/testbench-core": "^8.23.4",
-                "pda/pheanstalk": "^4.0",
-                "phpstan/phpstan": "^1.4.7",
-                "phpunit/phpunit": "^10.0.7",
-                "predis/predis": "^2.0.2",
-                "symfony/cache": "^6.2",
-                "symfony/http-client": "^6.2.4",
-                "symfony/psr-http-message-bridge": "^2.0"
+                "fakerphp/faker": "^1.24",
+                "guzzlehttp/promises": "^2.0.3",
+                "guzzlehttp/psr7": "^2.4",
+                "laravel/pint": "^1.18",
+                "league/flysystem-aws-s3-v3": "^3.25.1",
+                "league/flysystem-ftp": "^3.25.1",
+                "league/flysystem-path-prefixing": "^3.25.1",
+                "league/flysystem-read-only": "^3.25.1",
+                "league/flysystem-sftp-v3": "^3.25.1",
+                "mockery/mockery": "^1.6.10",
+                "orchestra/testbench-core": "^9.13.2",
+                "pda/pheanstalk": "^5.0.6",
+                "php-http/discovery": "^1.15",
+                "phpstan/phpstan": "^2.0",
+                "phpunit/phpunit": "^10.5.35|^11.3.6|^12.0.1",
+                "predis/predis": "^2.3",
+                "resend/resend-php": "^0.10.0",
+                "symfony/cache": "^7.0.3",
+                "symfony/http-client": "^7.0.3",
+                "symfony/psr-http-message-bridge": "^7.0.3",
+                "symfony/translation": "^7.0.3"
             },
             "suggest": {
                 "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).",
             },
             "suggest": {
                 "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).",
-                "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.235.5).",
-                "brianium/paratest": "Required to run tests in parallel (^6.0).",
-                "doctrine/dbal": "Required to rename columns and drop SQLite columns (^3.5.1).",
+                "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).",
+                "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).",
                 "ext-apcu": "Required to use the APC cache driver.",
                 "ext-fileinfo": "Required to use the Filesystem class.",
                 "ext-ftp": "Required to use the Flysystem FTP driver.",
                 "ext-apcu": "Required to use the APC cache driver.",
                 "ext-fileinfo": "Required to use the Filesystem class.",
                 "ext-ftp": "Required to use the Flysystem FTP driver.",
                 "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.",
                 "ext-pdo": "Required to use all database features.",
                 "ext-posix": "Required to use all features of the queue worker.",
                 "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.",
                 "ext-pdo": "Required to use all database features.",
                 "ext-posix": "Required to use all features of the queue worker.",
-                "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0).",
+                "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).",
                 "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).",
                 "filp/whoops": "Required for friendly error pages in development (^2.14.3).",
                 "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).",
                 "filp/whoops": "Required for friendly error pages in development (^2.14.3).",
-                "guzzlehttp/guzzle": "Required to use the HTTP Client and the ping methods on schedules (^7.5).",
                 "laravel/tinker": "Required to use the tinker console command (^2.0).",
                 "laravel/tinker": "Required to use the tinker console command (^2.0).",
-                "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.0).",
-                "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.0).",
-                "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.3).",
-                "league/flysystem-read-only": "Required to use read-only disks (^3.3)",
-                "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.0).",
-                "mockery/mockery": "Required to use mocking (^1.5.1).",
-                "nyholm/psr7": "Required to use PSR-7 bridging features (^1.2).",
-                "pda/pheanstalk": "Required to use the beanstalk queue driver (^4.0).",
-                "phpunit/phpunit": "Required to use assertions and run tests (^9.5.8|^10.0.7).",
-                "predis/predis": "Required to use the predis connector (^2.0.2).",
+                "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).",
+                "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).",
+                "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.25.1).",
+                "league/flysystem-read-only": "Required to use read-only disks (^3.25.1)",
+                "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).",
+                "mockery/mockery": "Required to use mocking (^1.6).",
+                "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).",
+                "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).",
+                "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.3.6|^12.0.1).",
+                "predis/predis": "Required to use the predis connector (^2.3).",
                 "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
                 "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).",
                 "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).",
                 "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).",
-                "symfony/cache": "Required to PSR-6 cache bridge (^6.2).",
-                "symfony/filesystem": "Required to enable support for relative symbolic links (^6.2).",
-                "symfony/http-client": "Required to enable support for the Symfony API mail transports (^6.2).",
-                "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^6.2).",
-                "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^6.2).",
-                "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^2.0)."
+                "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).",
+                "symfony/cache": "Required to PSR-6 cache bridge (^7.0).",
+                "symfony/filesystem": "Required to enable support for relative symbolic links (^7.0).",
+                "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.0).",
+                "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.0).",
+                "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.0).",
+                "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.0)."
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "10.x-dev"
+                    "dev-master": "11.x-dev"
                 }
             },
             "autoload": {
                 "files": [
                 }
             },
             "autoload": {
                 "files": [
+                    "src/Illuminate/Collections/functions.php",
                     "src/Illuminate/Collections/helpers.php",
                     "src/Illuminate/Events/functions.php",
                     "src/Illuminate/Filesystem/functions.php",
                     "src/Illuminate/Foundation/helpers.php",
                     "src/Illuminate/Collections/helpers.php",
                     "src/Illuminate/Events/functions.php",
                     "src/Illuminate/Filesystem/functions.php",
                     "src/Illuminate/Foundation/helpers.php",
+                    "src/Illuminate/Log/functions.php",
+                    "src/Illuminate/Support/functions.php",
                     "src/Illuminate/Support/helpers.php"
                 ],
                 "psr-4": {
                     "src/Illuminate/Support/helpers.php"
                 ],
                 "psr-4": {
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
                 "issues": "https://github.com/laravel/framework/issues",
                 "source": "https://github.com/laravel/framework"
             },
-            "time": "2024-03-21T13:36:36+00:00"
+            "time": "2025-06-03T14:01:40+00:00"
         },
         {
             "name": "laravel/prompts",
         },
         {
             "name": "laravel/prompts",
-            "version": "v0.1.17",
+            "version": "v0.3.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/prompts.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/prompts.git",
-                "reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5"
+                "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/prompts/zipball/8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5",
-                "reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5",
+                "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1",
+                "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
+                "composer-runtime-api": "^2.2",
                 "ext-mbstring": "*",
                 "ext-mbstring": "*",
-                "illuminate/collections": "^10.0|^11.0",
                 "php": "^8.1",
                 "symfony/console": "^6.2|^7.0"
             },
                 "php": "^8.1",
                 "symfony/console": "^6.2|^7.0"
             },
                 "laravel/framework": ">=10.17.0 <10.25.0"
             },
             "require-dev": {
                 "laravel/framework": ">=10.17.0 <10.25.0"
             },
             "require-dev": {
+                "illuminate/collections": "^10.0|^11.0|^12.0",
                 "mockery/mockery": "^1.5",
                 "mockery/mockery": "^1.5",
-                "pestphp/pest": "^2.3",
+                "pestphp/pest": "^2.3|^3.4",
                 "phpstan/phpstan": "^1.11",
                 "phpstan/phpstan-mockery": "^1.1"
             },
                 "phpstan/phpstan": "^1.11",
                 "phpstan/phpstan-mockery": "^1.1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-main": "0.1.x-dev"
+                    "dev-main": "0.3.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "license": [
                 "MIT"
             ],
             "license": [
                 "MIT"
             ],
+            "description": "Add beautiful and user-friendly forms to your command-line applications.",
             "support": {
                 "issues": "https://github.com/laravel/prompts/issues",
             "support": {
                 "issues": "https://github.com/laravel/prompts/issues",
-                "source": "https://github.com/laravel/prompts/tree/v0.1.17"
+                "source": "https://github.com/laravel/prompts/tree/v0.3.5"
+            },
+            "time": "2025-02-11T13:34:40+00:00"
+        },
+        {
+            "name": "laravel/reverb",
+            "version": "v1.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/laravel/reverb.git",
+                "reference": "c82751070c9a5397095d91ff743aefb0549917c3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/laravel/reverb/zipball/c82751070c9a5397095d91ff743aefb0549917c3",
+                "reference": "c82751070c9a5397095d91ff743aefb0549917c3",
+                "shasum": ""
+            },
+            "require": {
+                "clue/redis-react": "^2.6",
+                "guzzlehttp/psr7": "^2.6",
+                "illuminate/console": "^10.47|^11.0|^12.0",
+                "illuminate/contracts": "^10.47|^11.0|^12.0",
+                "illuminate/http": "^10.47|^11.0|^12.0",
+                "illuminate/support": "^10.47|^11.0|^12.0",
+                "laravel/prompts": "^0.1.15|^0.2.0|^0.3.0",
+                "php": "^8.2",
+                "pusher/pusher-php-server": "^7.2",
+                "ratchet/rfc6455": "^0.4",
+                "react/promise-timer": "^1.10",
+                "react/socket": "^1.14",
+                "symfony/console": "^6.0|^7.0",
+                "symfony/http-foundation": "^6.3|^7.0"
+            },
+            "require-dev": {
+                "orchestra/testbench": "^8.0|^9.0|^10.0",
+                "pestphp/pest": "^2.0|^3.0",
+                "phpstan/phpstan": "^1.10",
+                "ratchet/pawl": "^0.4.1",
+                "react/async": "^4.2",
+                "react/http": "^1.9"
+            },
+            "type": "library",
+            "extra": {
+                "laravel": {
+                    "aliases": {
+                        "Output": "Laravel\\Reverb\\Output"
+                    },
+                    "providers": [
+                        "Laravel\\Reverb\\ApplicationManagerServiceProvider",
+                        "Laravel\\Reverb\\ReverbServiceProvider"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Laravel\\Reverb\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Taylor Otwell",
+                    "email": "taylor@laravel.com"
+                },
+                {
+                    "name": "Joe Dixon",
+                    "email": "joe@laravel.com"
+                }
+            ],
+            "description": "Laravel Reverb provides a real-time WebSocket communication backend for Laravel applications.",
+            "keywords": [
+                "WebSockets",
+                "laravel",
+                "real-time",
+                "websocket"
+            ],
+            "support": {
+                "issues": "https://github.com/laravel/reverb/issues",
+                "source": "https://github.com/laravel/reverb/tree/v1.5.1"
             },
             },
-            "time": "2024-03-13T16:05:43+00:00"
+            "time": "2025-06-16T13:48:47+00:00"
         },
         {
             "name": "laravel/sanctum",
         },
         {
             "name": "laravel/sanctum",
-            "version": "v3.3.3",
+            "version": "v4.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/sanctum.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/sanctum.git",
-                "reference": "8c104366459739f3ada0e994bcd3e6fd681ce3d5"
+                "reference": "a360a6a1fd2400ead4eb9b6a9c1bb272939194f5"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/sanctum/zipball/8c104366459739f3ada0e994bcd3e6fd681ce3d5",
-                "reference": "8c104366459739f3ada0e994bcd3e6fd681ce3d5",
+                "url": "https://api.github.com/repos/laravel/sanctum/zipball/a360a6a1fd2400ead4eb9b6a9c1bb272939194f5",
+                "reference": "a360a6a1fd2400ead4eb9b6a9c1bb272939194f5",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "illuminate/console": "^9.21|^10.0",
-                "illuminate/contracts": "^9.21|^10.0",
-                "illuminate/database": "^9.21|^10.0",
-                "illuminate/support": "^9.21|^10.0",
-                "php": "^8.0.2"
+                "illuminate/console": "^11.0|^12.0",
+                "illuminate/contracts": "^11.0|^12.0",
+                "illuminate/database": "^11.0|^12.0",
+                "illuminate/support": "^11.0|^12.0",
+                "php": "^8.2",
+                "symfony/console": "^7.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "mockery/mockery": "^1.0",
-                "orchestra/testbench": "^7.28.2|^8.8.3",
+                "mockery/mockery": "^1.6",
+                "orchestra/testbench": "^9.0|^10.0",
                 "phpstan/phpstan": "^1.10",
                 "phpstan/phpstan": "^1.10",
-                "phpunit/phpunit": "^9.6"
+                "phpunit/phpunit": "^11.3"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-master": "3.x-dev"
-                },
                 "laravel": {
                     "providers": [
                         "Laravel\\Sanctum\\SanctumServiceProvider"
                 "laravel": {
                     "providers": [
                         "Laravel\\Sanctum\\SanctumServiceProvider"
                 "issues": "https://github.com/laravel/sanctum/issues",
                 "source": "https://github.com/laravel/sanctum"
             },
                 "issues": "https://github.com/laravel/sanctum/issues",
                 "source": "https://github.com/laravel/sanctum"
             },
-            "time": "2023-12-19T18:44:48+00:00"
+            "time": "2025-04-23T13:03:38+00:00"
         },
         {
             "name": "laravel/serializable-closure",
         },
         {
             "name": "laravel/serializable-closure",
-            "version": "v1.3.3",
+            "version": "v2.0.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/serializable-closure.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/serializable-closure.git",
-                "reference": "3dbf8a8e914634c48d389c1234552666b3d43754"
+                "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/3dbf8a8e914634c48d389c1234552666b3d43754",
-                "reference": "3dbf8a8e914634c48d389c1234552666b3d43754",
+                "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841",
+                "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": "^7.3|^8.0"
+                "php": "^8.1"
             },
             "require-dev": {
             },
             "require-dev": {
-                "nesbot/carbon": "^2.61",
-                "pestphp/pest": "^1.21.3",
-                "phpstan/phpstan": "^1.8.2",
-                "symfony/var-dumper": "^5.4.11"
+                "illuminate/support": "^10.0|^11.0|^12.0",
+                "nesbot/carbon": "^2.67|^3.0",
+                "pestphp/pest": "^2.36|^3.0",
+                "phpstan/phpstan": "^2.0",
+                "symfony/var-dumper": "^6.2.0|^7.0.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.x-dev"
+                    "dev-master": "2.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "issues": "https://github.com/laravel/serializable-closure/issues",
                 "source": "https://github.com/laravel/serializable-closure"
             },
                 "issues": "https://github.com/laravel/serializable-closure/issues",
                 "source": "https://github.com/laravel/serializable-closure"
             },
-            "time": "2023-11-08T14:08:06+00:00"
+            "time": "2025-03-19T13:51:03+00:00"
         },
         {
             "name": "laravel/tinker",
         },
         {
             "name": "laravel/tinker",
-            "version": "v2.9.0",
+            "version": "v2.10.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/tinker.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/tinker.git",
-                "reference": "502e0fe3f0415d06d5db1f83a472f0f3b754bafe"
+                "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/tinker/zipball/502e0fe3f0415d06d5db1f83a472f0f3b754bafe",
-                "reference": "502e0fe3f0415d06d5db1f83a472f0f3b754bafe",
+                "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3",
+                "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
-                "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
-                "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
+                "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
+                "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
+                "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0",
                 "php": "^7.2.5|^8.0",
                 "psy/psysh": "^0.11.1|^0.12.0",
                 "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0"
                 "php": "^7.2.5|^8.0",
                 "psy/psysh": "^0.11.1|^0.12.0",
                 "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0"
             "require-dev": {
                 "mockery/mockery": "~1.3.3|^1.4.2",
                 "phpstan/phpstan": "^1.10",
             "require-dev": {
                 "mockery/mockery": "~1.3.3|^1.4.2",
                 "phpstan/phpstan": "^1.10",
-                "phpunit/phpunit": "^8.5.8|^9.3.3"
+                "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0"
             },
             "suggest": {
             },
             "suggest": {
-                "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0)."
+                "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)."
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
             ],
             "support": {
                 "issues": "https://github.com/laravel/tinker/issues",
             ],
             "support": {
                 "issues": "https://github.com/laravel/tinker/issues",
-                "source": "https://github.com/laravel/tinker/tree/v2.9.0"
+                "source": "https://github.com/laravel/tinker/tree/v2.10.1"
             },
             },
-            "time": "2024-01-04T16:10:04+00:00"
+            "time": "2025-01-27T14:24:01+00:00"
         },
         {
             "name": "laravel/ui",
         },
         {
             "name": "laravel/ui",
-            "version": "v4.5.1",
+            "version": "v4.6.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/ui.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/ui.git",
-                "reference": "a3562953123946996a503159199d6742d5534e61"
+                "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/ui/zipball/a3562953123946996a503159199d6742d5534e61",
-                "reference": "a3562953123946996a503159199d6742d5534e61",
+                "url": "https://api.github.com/repos/laravel/ui/zipball/7d6ffa38d79f19c9b3e70a751a9af845e8f41d88",
+                "reference": "7d6ffa38d79f19c9b3e70a751a9af845e8f41d88",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "illuminate/console": "^9.21|^10.0|^11.0",
-                "illuminate/filesystem": "^9.21|^10.0|^11.0",
-                "illuminate/support": "^9.21|^10.0|^11.0",
-                "illuminate/validation": "^9.21|^10.0|^11.0",
+                "illuminate/console": "^9.21|^10.0|^11.0|^12.0",
+                "illuminate/filesystem": "^9.21|^10.0|^11.0|^12.0",
+                "illuminate/support": "^9.21|^10.0|^11.0|^12.0",
+                "illuminate/validation": "^9.21|^10.0|^11.0|^12.0",
                 "php": "^8.0",
                 "symfony/console": "^6.0|^7.0"
             },
             "require-dev": {
                 "php": "^8.0",
                 "symfony/console": "^6.0|^7.0"
             },
             "require-dev": {
-                "orchestra/testbench": "^7.35|^8.15|^9.0",
-                "phpunit/phpunit": "^9.3|^10.4|^11.0"
+                "orchestra/testbench": "^7.35|^8.15|^9.0|^10.0",
+                "phpunit/phpunit": "^9.3|^10.4|^11.5"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-master": "4.x-dev"
-                },
                 "laravel": {
                     "providers": [
                         "Laravel\\Ui\\UiServiceProvider"
                     ]
                 "laravel": {
                     "providers": [
                         "Laravel\\Ui\\UiServiceProvider"
                     ]
+                },
+                "branch-alias": {
+                    "dev-master": "4.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "ui"
             ],
             "support": {
                 "ui"
             ],
             "support": {
-                "source": "https://github.com/laravel/ui/tree/v4.5.1"
+                "source": "https://github.com/laravel/ui/tree/v4.6.1"
             },
             },
-            "time": "2024-03-21T18:12:29+00:00"
+            "time": "2025-01-28T15:15:29+00:00"
         },
         {
             "name": "league/commonmark",
         },
         {
             "name": "league/commonmark",
-            "version": "2.4.2",
+            "version": "2.7.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thephpleague/commonmark.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thephpleague/commonmark.git",
-                "reference": "91c24291965bd6d7c46c46a12ba7492f83b1cadf"
+                "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/91c24291965bd6d7c46c46a12ba7492f83b1cadf",
-                "reference": "91c24291965bd6d7c46c46a12ba7492f83b1cadf",
+                "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6fbb36d44824ed4091adbcf4c7d4a3923cdb3405",
+                "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "cebe/markdown": "^1.0",
             },
             "require-dev": {
                 "cebe/markdown": "^1.0",
-                "commonmark/cmark": "0.30.3",
-                "commonmark/commonmark.js": "0.30.0",
+                "commonmark/cmark": "0.31.1",
+                "commonmark/commonmark.js": "0.31.1",
                 "composer/package-versions-deprecated": "^1.8",
                 "embed/embed": "^4.4",
                 "erusev/parsedown": "^1.0",
                 "composer/package-versions-deprecated": "^1.8",
                 "embed/embed": "^4.4",
                 "erusev/parsedown": "^1.0",
                 "phpstan/phpstan": "^1.8.2",
                 "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0",
                 "scrutinizer/ocular": "^1.8.1",
                 "phpstan/phpstan": "^1.8.2",
                 "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0",
                 "scrutinizer/ocular": "^1.8.1",
-                "symfony/finder": "^5.3 | ^6.0 || ^7.0",
-                "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 || ^7.0",
+                "symfony/finder": "^5.3 | ^6.0 | ^7.0",
+                "symfony/process": "^5.4 | ^6.0 | ^7.0",
+                "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0",
                 "unleashedtech/php-coding-standard": "^3.1.1",
                 "vimeo/psalm": "^4.24.0 || ^5.0.0"
             },
                 "unleashedtech/php-coding-standard": "^3.1.1",
                 "vimeo/psalm": "^4.24.0 || ^5.0.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-main": "2.5-dev"
+                    "dev-main": "2.8-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-02-02T11:59:32+00:00"
+            "time": "2025-05-05T12:20:28+00:00"
         },
         {
             "name": "league/config",
         },
         {
             "name": "league/config",
         },
         {
             "name": "league/flysystem",
         },
         {
             "name": "league/flysystem",
-            "version": "3.26.0",
+            "version": "3.29.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thephpleague/flysystem.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thephpleague/flysystem.git",
-                "reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be"
+                "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/072735c56cc0da00e10716dd90d5a7f7b40b36be",
-                "reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be",
+                "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319",
+                "reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "composer/semver": "^3.0",
                 "ext-fileinfo": "*",
                 "ext-ftp": "*",
                 "composer/semver": "^3.0",
                 "ext-fileinfo": "*",
                 "ext-ftp": "*",
+                "ext-mongodb": "^1.3",
                 "ext-zip": "*",
                 "friendsofphp/php-cs-fixer": "^3.5",
                 "google/cloud-storage": "^1.23",
                 "ext-zip": "*",
                 "friendsofphp/php-cs-fixer": "^3.5",
                 "google/cloud-storage": "^1.23",
+                "guzzlehttp/psr7": "^2.6",
                 "microsoft/azure-storage-blob": "^1.1",
                 "microsoft/azure-storage-blob": "^1.1",
+                "mongodb/mongodb": "^1.2",
                 "phpseclib/phpseclib": "^3.0.36",
                 "phpstan/phpstan": "^1.10",
                 "phpunit/phpunit": "^9.5.11|^10.0",
                 "phpseclib/phpseclib": "^3.0.36",
                 "phpstan/phpstan": "^1.10",
                 "phpunit/phpunit": "^9.5.11|^10.0",
             ],
             "support": {
                 "issues": "https://github.com/thephpleague/flysystem/issues",
             ],
             "support": {
                 "issues": "https://github.com/thephpleague/flysystem/issues",
-                "source": "https://github.com/thephpleague/flysystem/tree/3.26.0"
+                "source": "https://github.com/thephpleague/flysystem/tree/3.29.1"
             },
             },
-            "funding": [
-                {
-                    "url": "https://ecologi.com/frankdejonge",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/frankdejonge",
-                    "type": "github"
-                }
-            ],
-            "time": "2024-03-25T11:49:53+00:00"
+            "time": "2024-10-08T08:58:34+00:00"
         },
         {
             "name": "league/flysystem-local",
         },
         {
             "name": "league/flysystem-local",
-            "version": "3.25.1",
+            "version": "3.29.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thephpleague/flysystem-local.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thephpleague/flysystem-local.git",
-                "reference": "61a6a90d6e999e4ddd9ce5adb356de0939060b92"
+                "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/61a6a90d6e999e4ddd9ce5adb356de0939060b92",
-                "reference": "61a6a90d6e999e4ddd9ce5adb356de0939060b92",
+                "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27",
+                "reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "local"
             ],
             "support": {
                 "local"
             ],
             "support": {
-                "source": "https://github.com/thephpleague/flysystem-local/tree/3.25.1"
+                "source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0"
+            },
+            "time": "2024-08-09T21:24:39+00:00"
+        },
+        {
+            "name": "league/mime-type-detection",
+            "version": "1.16.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/mime-type-detection.git",
+                "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9",
+                "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9",
+                "shasum": ""
+            },
+            "require": {
+                "ext-fileinfo": "*",
+                "php": "^7.4 || ^8.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^3.2",
+                "phpstan/phpstan": "^0.12.68",
+                "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "League\\MimeTypeDetection\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Frank de Jonge",
+                    "email": "info@frankdejonge.nl"
+                }
+            ],
+            "description": "Mime-type detection for Flysystem",
+            "support": {
+                "issues": "https://github.com/thephpleague/mime-type-detection/issues",
+                "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/frankdejonge",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/league/flysystem",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-09-21T08:32:55+00:00"
+        },
+        {
+            "name": "league/uri",
+            "version": "7.5.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/uri.git",
+                "reference": "81fb5145d2644324614cc532b28efd0215bda430"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430",
+                "reference": "81fb5145d2644324614cc532b28efd0215bda430",
+                "shasum": ""
+            },
+            "require": {
+                "league/uri-interfaces": "^7.5",
+                "php": "^8.1"
+            },
+            "conflict": {
+                "league/uri-schemes": "^1.0"
+            },
+            "suggest": {
+                "ext-bcmath": "to improve IPV4 host parsing",
+                "ext-fileinfo": "to create Data URI from file contennts",
+                "ext-gmp": "to improve IPV4 host parsing",
+                "ext-intl": "to handle IDN host with the best performance",
+                "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain",
+                "league/uri-components": "Needed to easily manipulate URI objects components",
+                "php-64bit": "to improve IPV4 host parsing",
+                "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "7.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "League\\Uri\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ignace Nyamagana Butera",
+                    "email": "nyamsprod@gmail.com",
+                    "homepage": "https://nyamsprod.com"
+                }
+            ],
+            "description": "URI manipulation library",
+            "homepage": "https://uri.thephpleague.com",
+            "keywords": [
+                "data-uri",
+                "file-uri",
+                "ftp",
+                "hostname",
+                "http",
+                "https",
+                "middleware",
+                "parse_str",
+                "parse_url",
+                "psr-7",
+                "query-string",
+                "querystring",
+                "rfc3986",
+                "rfc3987",
+                "rfc6570",
+                "uri",
+                "uri-template",
+                "url",
+                "ws"
+            ],
+            "support": {
+                "docs": "https://uri.thephpleague.com",
+                "forum": "https://thephpleague.slack.com",
+                "issues": "https://github.com/thephpleague/uri-src/issues",
+                "source": "https://github.com/thephpleague/uri/tree/7.5.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
-                    "url": "https://ecologi.com/frankdejonge",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/frankdejonge",
+                    "url": "https://github.com/sponsors/nyamsprod",
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-03-15T19:58:44+00:00"
+            "time": "2024-12-08T08:40:02+00:00"
         },
         {
         },
         {
-            "name": "league/mime-type-detection",
-            "version": "1.15.0",
+            "name": "league/uri-interfaces",
+            "version": "7.5.0",
             "source": {
                 "type": "git",
             "source": {
                 "type": "git",
-                "url": "https://github.com/thephpleague/mime-type-detection.git",
-                "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301"
+                "url": "https://github.com/thephpleague/uri-interfaces.git",
+                "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
-                "reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
+                "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742",
+                "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "ext-fileinfo": "*",
-                "php": "^7.4 || ^8.0"
+                "ext-filter": "*",
+                "php": "^8.1",
+                "psr/http-factory": "^1",
+                "psr/http-message": "^1.1 || ^2.0"
             },
             },
-            "require-dev": {
-                "friendsofphp/php-cs-fixer": "^3.2",
-                "phpstan/phpstan": "^0.12.68",
-                "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0"
+            "suggest": {
+                "ext-bcmath": "to improve IPV4 host parsing",
+                "ext-gmp": "to improve IPV4 host parsing",
+                "ext-intl": "to handle IDN host with the best performance",
+                "php-64bit": "to improve IPV4 host parsing",
+                "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
             },
             "type": "library",
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "7.x-dev"
+                }
+            },
             "autoload": {
                 "psr-4": {
             "autoload": {
                 "psr-4": {
-                    "League\\MimeTypeDetection\\": "src"
+                    "League\\Uri\\": ""
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
             ],
             "authors": [
                 {
             ],
             "authors": [
                 {
-                    "name": "Frank de Jonge",
-                    "email": "info@frankdejonge.nl"
+                    "name": "Ignace Nyamagana Butera",
+                    "email": "nyamsprod@gmail.com",
+                    "homepage": "https://nyamsprod.com"
                 }
             ],
                 }
             ],
-            "description": "Mime-type detection for Flysystem",
+            "description": "Common interfaces and classes for URI representation and interaction",
+            "homepage": "https://uri.thephpleague.com",
+            "keywords": [
+                "data-uri",
+                "file-uri",
+                "ftp",
+                "hostname",
+                "http",
+                "https",
+                "parse_str",
+                "parse_url",
+                "psr-7",
+                "query-string",
+                "querystring",
+                "rfc3986",
+                "rfc3987",
+                "rfc6570",
+                "uri",
+                "url",
+                "ws"
+            ],
             "support": {
             "support": {
-                "issues": "https://github.com/thephpleague/mime-type-detection/issues",
-                "source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0"
+                "docs": "https://uri.thephpleague.com",
+                "forum": "https://thephpleague.slack.com",
+                "issues": "https://github.com/thephpleague/uri-src/issues",
+                "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
-                    "url": "https://github.com/frankdejonge",
+                    "url": "https://github.com/sponsors/nyamsprod",
                     "type": "github"
                     "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/league/flysystem",
-                    "type": "tidelift"
                 }
             ],
                 }
             ],
-            "time": "2024-01-28T23:22:08+00:00"
+            "time": "2024-12-08T08:18:47+00:00"
         },
         {
             "name": "mollie/polyfill-libsodium",
         },
         {
             "name": "mollie/polyfill-libsodium",
                 "issues": "https://github.com/mollie/polyfill-libsodium/issues",
                 "source": "https://github.com/mollie/polyfill-libsodium/tree/master"
             },
                 "issues": "https://github.com/mollie/polyfill-libsodium/issues",
                 "source": "https://github.com/mollie/polyfill-libsodium/tree/master"
             },
+            "abandoned": true,
             "time": "2018-01-22T16:27:22+00:00"
         },
         {
             "name": "monolog/monolog",
             "time": "2018-01-22T16:27:22+00:00"
         },
         {
             "name": "monolog/monolog",
-            "version": "3.5.0",
+            "version": "3.9.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Seldaek/monolog.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Seldaek/monolog.git",
-                "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448"
+                "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448",
-                "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448",
+                "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6",
+                "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "guzzlehttp/psr7": "^2.2",
                 "mongodb/mongodb": "^1.8",
                 "php-amqplib/php-amqplib": "~2.4 || ^3",
                 "guzzlehttp/psr7": "^2.2",
                 "mongodb/mongodb": "^1.8",
                 "php-amqplib/php-amqplib": "~2.4 || ^3",
-                "phpstan/phpstan": "^1.9",
-                "phpstan/phpstan-deprecation-rules": "^1.0",
-                "phpstan/phpstan-strict-rules": "^1.4",
-                "phpunit/phpunit": "^10.1",
+                "php-console/php-console": "^3.1.8",
+                "phpstan/phpstan": "^2",
+                "phpstan/phpstan-deprecation-rules": "^2",
+                "phpstan/phpstan-strict-rules": "^2",
+                "phpunit/phpunit": "^10.5.17 || ^11.0.7",
                 "predis/predis": "^1.1 || ^2",
                 "predis/predis": "^1.1 || ^2",
-                "ruflin/elastica": "^7",
+                "rollbar/rollbar": "^4.0",
+                "ruflin/elastica": "^7 || ^8",
                 "symfony/mailer": "^5.4 || ^6",
                 "symfony/mime": "^5.4 || ^6"
             },
                 "symfony/mailer": "^5.4 || ^6",
                 "symfony/mime": "^5.4 || ^6"
             },
             ],
             "support": {
                 "issues": "https://github.com/Seldaek/monolog/issues",
             ],
             "support": {
                 "issues": "https://github.com/Seldaek/monolog/issues",
-                "source": "https://github.com/Seldaek/monolog/tree/3.5.0"
+                "source": "https://github.com/Seldaek/monolog/tree/3.9.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-10-27T15:32:31+00:00"
+            "time": "2025-03-24T10:02:05+00:00"
         },
         {
             "name": "nesbot/carbon",
         },
         {
             "name": "nesbot/carbon",
-            "version": "2.72.3",
+            "version": "2.73.0",
             "source": {
                 "type": "git",
             "source": {
                 "type": "git",
-                "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83"
+                "url": "https://github.com/CarbonPHP/carbon.git",
+                "reference": "9228ce90e1035ff2f0db84b40ec2e023ed802075"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/0c6fd108360c562f6e4fd1dedb8233b423e91c83",
-                "reference": "0c6fd108360c562f6e4fd1dedb8233b423e91c83",
+                "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/9228ce90e1035ff2f0db84b40ec2e023ed802075",
+                "reference": "9228ce90e1035ff2f0db84b40ec2e023ed802075",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "doctrine/orm": "^2.7 || ^3.0",
                 "friendsofphp/php-cs-fixer": "^3.0",
                 "kylekatarnls/multi-tester": "^2.0",
                 "doctrine/orm": "^2.7 || ^3.0",
                 "friendsofphp/php-cs-fixer": "^3.0",
                 "kylekatarnls/multi-tester": "^2.0",
-                "ondrejmirtes/better-reflection": "*",
+                "ondrejmirtes/better-reflection": "<6",
                 "phpmd/phpmd": "^2.9",
                 "phpstan/extension-installer": "^1.0",
                 "phpstan/phpstan": "^0.12.99 || ^1.7.14",
                 "phpmd/phpmd": "^2.9",
                 "phpstan/extension-installer": "^1.0",
                 "phpstan/phpstan": "^0.12.99 || ^1.7.14",
             ],
             "type": "library",
             "extra": {
             ],
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-3.x": "3.x-dev",
-                    "dev-master": "2.x-dev"
-                },
                 "laravel": {
                     "providers": [
                         "Carbon\\Laravel\\ServiceProvider"
                 "laravel": {
                     "providers": [
                         "Carbon\\Laravel\\ServiceProvider"
                     "includes": [
                         "extension.neon"
                     ]
                     "includes": [
                         "extension.neon"
                     ]
+                },
+                "branch-alias": {
+                    "dev-2.x": "2.x-dev",
+                    "dev-master": "3.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-25T10:35:09+00:00"
+            "time": "2025-01-08T20:10:23+00:00"
         },
         {
             "name": "nette/schema",
         },
         {
             "name": "nette/schema",
-            "version": "v1.3.0",
+            "version": "v1.3.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nette/schema.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nette/schema.git",
-                "reference": "a6d3a6d1f545f01ef38e60f375d1cf1f4de98188"
+                "reference": "da801d52f0354f70a638673c4a0f04e16529431d"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nette/schema/zipball/a6d3a6d1f545f01ef38e60f375d1cf1f4de98188",
-                "reference": "a6d3a6d1f545f01ef38e60f375d1cf1f4de98188",
+                "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d",
+                "reference": "da801d52f0354f70a638673c4a0f04e16529431d",
                 "shasum": ""
             },
             "require": {
                 "nette/utils": "^4.0",
                 "shasum": ""
             },
             "require": {
                 "nette/utils": "^4.0",
-                "php": "8.1 - 8.3"
+                "php": "8.1 - 8.4"
             },
             "require-dev": {
             },
             "require-dev": {
-                "nette/tester": "^2.4",
+                "nette/tester": "^2.5.2",
                 "phpstan/phpstan-nette": "^1.0",
                 "tracy/tracy": "^2.8"
             },
                 "phpstan/phpstan-nette": "^1.0",
                 "tracy/tracy": "^2.8"
             },
             ],
             "support": {
                 "issues": "https://github.com/nette/schema/issues",
             ],
             "support": {
                 "issues": "https://github.com/nette/schema/issues",
-                "source": "https://github.com/nette/schema/tree/v1.3.0"
+                "source": "https://github.com/nette/schema/tree/v1.3.2"
             },
             },
-            "time": "2023-12-11T11:54:22+00:00"
+            "time": "2024-10-06T23:10:23+00:00"
         },
         {
             "name": "nette/utils",
         },
         {
             "name": "nette/utils",
-            "version": "v4.0.4",
+            "version": "v4.0.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nette/utils.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nette/utils.git",
-                "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218"
+                "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nette/utils/zipball/d3ad0aa3b9f934602cb3e3902ebccf10be34d218",
-                "reference": "d3ad0aa3b9f934602cb3e3902ebccf10be34d218",
+                "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2",
+                "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.0 <8.4"
+                "php": "8.0 - 8.4"
             },
             "conflict": {
                 "nette/finder": "<3",
             },
             "conflict": {
                 "nette/finder": "<3",
             ],
             "support": {
                 "issues": "https://github.com/nette/utils/issues",
             ],
             "support": {
                 "issues": "https://github.com/nette/utils/issues",
-                "source": "https://github.com/nette/utils/tree/v4.0.4"
+                "source": "https://github.com/nette/utils/tree/v4.0.7"
             },
             },
-            "time": "2024-01-17T16:50:36+00:00"
+            "time": "2025-06-03T04:55:08+00:00"
         },
         {
             "name": "nikic/php-parser",
         },
         {
             "name": "nikic/php-parser",
-            "version": "v5.0.2",
+            "version": "v5.5.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nikic/PHP-Parser.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nikic/PHP-Parser.git",
-                "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13"
+                "reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13",
-                "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
+                "reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "ircmaxell/php-yacc": "^0.0.7",
             },
             "require-dev": {
                 "ircmaxell/php-yacc": "^0.0.7",
-                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
+                "phpunit/phpunit": "^9.0"
             },
             "bin": [
                 "bin/php-parse"
             },
             "bin": [
                 "bin/php-parse"
             ],
             "support": {
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
             ],
             "support": {
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
-                "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2"
+                "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
             },
             },
-            "time": "2024-03-05T20:51:40+00:00"
+            "time": "2025-05-31T08:24:38+00:00"
         },
         {
             "name": "nunomaduro/termwind",
         },
         {
             "name": "nunomaduro/termwind",
-            "version": "v1.15.1",
+            "version": "v2.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nunomaduro/termwind.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nunomaduro/termwind.git",
-                "reference": "8ab0b32c8caa4a2e09700ea32925441385e4a5dc"
+                "reference": "dfa08f390e509967a15c22493dc0bac5733d9123"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/8ab0b32c8caa4a2e09700ea32925441385e4a5dc",
-                "reference": "8ab0b32c8caa4a2e09700ea32925441385e4a5dc",
+                "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123",
+                "reference": "dfa08f390e509967a15c22493dc0bac5733d9123",
                 "shasum": ""
             },
             "require": {
                 "ext-mbstring": "*",
                 "shasum": ""
             },
             "require": {
                 "ext-mbstring": "*",
-                "php": "^8.0",
-                "symfony/console": "^5.3.0|^6.0.0"
+                "php": "^8.2",
+                "symfony/console": "^7.2.6"
             },
             "require-dev": {
             },
             "require-dev": {
-                "ergebnis/phpstan-rules": "^1.0.",
-                "illuminate/console": "^8.0|^9.0",
-                "illuminate/support": "^8.0|^9.0",
-                "laravel/pint": "^1.0.0",
-                "pestphp/pest": "^1.21.0",
-                "pestphp/pest-plugin-mock": "^1.0",
-                "phpstan/phpstan": "^1.4.6",
-                "phpstan/phpstan-strict-rules": "^1.1.0",
-                "symfony/var-dumper": "^5.2.7|^6.0.0",
+                "illuminate/console": "^11.44.7",
+                "laravel/pint": "^1.22.0",
+                "mockery/mockery": "^1.6.12",
+                "pestphp/pest": "^2.36.0 || ^3.8.2",
+                "phpstan/phpstan": "^1.12.25",
+                "phpstan/phpstan-strict-rules": "^1.6.2",
+                "symfony/var-dumper": "^7.2.6",
                 "thecodingmachine/phpstan-strict-rules": "^1.0.0"
             },
             "type": "library",
                 "thecodingmachine/phpstan-strict-rules": "^1.0.0"
             },
             "type": "library",
                     "providers": [
                         "Termwind\\Laravel\\TermwindServiceProvider"
                     ]
                     "providers": [
                         "Termwind\\Laravel\\TermwindServiceProvider"
                     ]
+                },
+                "branch-alias": {
+                    "dev-2.x": "2.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/nunomaduro/termwind/issues",
             ],
             "support": {
                 "issues": "https://github.com/nunomaduro/termwind/issues",
-                "source": "https://github.com/nunomaduro/termwind/tree/v1.15.1"
+                "source": "https://github.com/nunomaduro/termwind/tree/v2.3.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-02-08T01:06:31+00:00"
-        },
-        {
-            "name": "paragonie/random_compat",
-            "version": "v9.99.100",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/paragonie/random_compat.git",
-                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
-                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">= 7"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "4.*|5.*",
-                "vimeo/psalm": "^1"
-            },
-            "suggest": {
-                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
-            },
-            "type": "library",
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Paragon Initiative Enterprises",
-                    "email": "security@paragonie.com",
-                    "homepage": "https://paragonie.com"
-                }
-            ],
-            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
-            "keywords": [
-                "csprng",
-                "polyfill",
-                "pseudorandom",
-                "random"
-            ],
-            "support": {
-                "email": "info@paragonie.com",
-                "issues": "https://github.com/paragonie/random_compat/issues",
-                "source": "https://github.com/paragonie/random_compat"
-            },
-            "time": "2020-10-15T08:29:30+00:00"
+            "time": "2025-05-08T08:14:37+00:00"
         },
         {
             "name": "paragonie/sodium_compat",
         },
         {
             "name": "paragonie/sodium_compat",
-            "version": "v1.20.1",
+            "version": "v2.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/paragonie/sodium_compat.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/paragonie/sodium_compat.git",
-                "reference": "1840b98d228bdad83869b191d7e51f9bb6624d8d"
+                "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/1840b98d228bdad83869b191d7e51f9bb6624d8d",
-                "reference": "1840b98d228bdad83869b191d7e51f9bb6624d8d",
+                "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/a673d5f310477027cead2e2f2b6db5d8368157cb",
+                "reference": "a673d5f310477027cead2e2f2b6db5d8368157cb",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "paragonie/random_compat": ">=1",
-                "php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7|^8"
+                "php": "^8.1",
+                "php-64bit": "*"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^3|^4|^5|^6|^7|^8|^9"
+                "phpunit/phpunit": "^7|^8|^9",
+                "vimeo/psalm": "^4|^5"
             },
             "suggest": {
             },
             "suggest": {
-                "ext-libsodium": "PHP < 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security.",
-                "ext-sodium": "PHP >= 7.0: Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
+                "ext-sodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
             },
             "type": "library",
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
             "autoload": {
                 "files": [
                     "autoload.php"
             "autoload": {
                 "files": [
                     "autoload.php"
             ],
             "support": {
                 "issues": "https://github.com/paragonie/sodium_compat/issues",
             ],
             "support": {
                 "issues": "https://github.com/paragonie/sodium_compat/issues",
-                "source": "https://github.com/paragonie/sodium_compat/tree/v1.20.1"
+                "source": "https://github.com/paragonie/sodium_compat/tree/v2.1.0"
             },
             },
-            "time": "2024-04-05T21:00:10+00:00"
+            "time": "2024-09-04T12:51:01+00:00"
         },
         {
             "name": "patrickschur/language-detection",
         },
         {
             "name": "patrickschur/language-detection",
-            "version": "v5.3.0",
+            "version": "v5.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/patrickschur/language-detection.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/patrickschur/language-detection.git",
-                "reference": "b8da335336c09fa6814fe0ca0d6d506c357cd7b9"
+                "reference": "df8d32021b2ef9fde52e6fcccb83e3806822c9c6"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/patrickschur/language-detection/zipball/b8da335336c09fa6814fe0ca0d6d506c357cd7b9",
-                "reference": "b8da335336c09fa6814fe0ca0d6d506c357cd7b9",
+                "url": "https://api.github.com/repos/patrickschur/language-detection/zipball/df8d32021b2ef9fde52e6fcccb83e3806822c9c6",
+                "reference": "df8d32021b2ef9fde52e6fcccb83e3806822c9c6",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/patrickschur/language-detection/issues",
             ],
             "support": {
                 "issues": "https://github.com/patrickschur/language-detection/issues",
-                "source": "https://github.com/patrickschur/language-detection/tree/v5.3.0"
+                "source": "https://github.com/patrickschur/language-detection/tree/v5.3.1"
             },
             },
-            "time": "2023-08-18T22:46:39+00:00"
+            "time": "2025-03-25T22:47:08+00:00"
         },
         {
             "name": "phpoption/phpoption",
         },
         {
             "name": "phpoption/phpoption",
-            "version": "1.9.2",
+            "version": "1.9.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/schmittjoh/php-option.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/schmittjoh/php-option.git",
-                "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820"
+                "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/80735db690fe4fc5c76dfa7f9b770634285fa820",
-                "reference": "80735db690fe4fc5c76dfa7f9b770634285fa820",
+                "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54",
+                "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
-                "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2"
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28"
             },
             "type": "library",
             "extra": {
                 "bamarni-bin": {
                     "bin-links": true,
             },
             "type": "library",
             "extra": {
                 "bamarni-bin": {
                     "bin-links": true,
-                    "forward-command": true
+                    "forward-command": false
                 },
                 "branch-alias": {
                     "dev-master": "1.9-dev"
                 },
                 "branch-alias": {
                     "dev-master": "1.9-dev"
             ],
             "support": {
                 "issues": "https://github.com/schmittjoh/php-option/issues",
             ],
             "support": {
                 "issues": "https://github.com/schmittjoh/php-option/issues",
-                "source": "https://github.com/schmittjoh/php-option/tree/1.9.2"
+                "source": "https://github.com/schmittjoh/php-option/tree/1.9.3"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-11-12T21:59:55+00:00"
-        },
-        {
-            "name": "psr/cache",
-            "version": "3.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/cache.git",
-                "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
-                "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=8.0.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\Cache\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "https://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interface for caching libraries",
-            "keywords": [
-                "cache",
-                "psr",
-                "psr-6"
-            ],
-            "support": {
-                "source": "https://github.com/php-fig/cache/tree/3.0.0"
-            },
-            "time": "2021-02-03T23:26:27+00:00"
+            "time": "2024-07-20T21:41:07+00:00"
         },
         {
             "name": "psr/clock",
         },
         {
             "name": "psr/clock",
         },
         {
             "name": "psr/http-factory",
         },
         {
             "name": "psr/http-factory",
-            "version": "1.0.2",
+            "version": "1.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-factory.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/http-factory.git",
-                "reference": "e616d01114759c4c489f93b099585439f795fe35"
+                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
-                "reference": "e616d01114759c4c489f93b099585439f795fe35",
+                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
+                "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.0.0",
+                "php": ">=7.1",
                 "psr/http-message": "^1.0 || ^2.0"
             },
             "type": "library",
                 "psr/http-message": "^1.0 || ^2.0"
             },
             "type": "library",
                     "homepage": "https://www.php-fig.org/"
                 }
             ],
                     "homepage": "https://www.php-fig.org/"
                 }
             ],
-            "description": "Common interfaces for PSR-7 HTTP message factories",
+            "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories",
             "keywords": [
                 "factory",
                 "http",
             "keywords": [
                 "factory",
                 "http",
                 "response"
             ],
             "support": {
                 "response"
             ],
             "support": {
-                "source": "https://github.com/php-fig/http-factory/tree/1.0.2"
+                "source": "https://github.com/php-fig/http-factory"
             },
             },
-            "time": "2023-04-10T20:10:41+00:00"
+            "time": "2024-04-15T12:06:14+00:00"
         },
         {
             "name": "psr/http-message",
         },
         {
             "name": "psr/http-message",
         },
         {
             "name": "psr/log",
         },
         {
             "name": "psr/log",
-            "version": "3.0.0",
+            "version": "3.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/log.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/php-fig/log.git",
-                "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001"
+                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001",
-                "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+                "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "psr-3"
             ],
             "support": {
                 "psr-3"
             ],
             "support": {
-                "source": "https://github.com/php-fig/log/tree/3.0.0"
+                "source": "https://github.com/php-fig/log/tree/3.0.2"
             },
             },
-            "time": "2021-07-14T16:46:02+00:00"
+            "time": "2024-09-11T13:17:53+00:00"
         },
         {
             "name": "psr/simple-cache",
         },
         {
             "name": "psr/simple-cache",
         },
         {
             "name": "psy/psysh",
         },
         {
             "name": "psy/psysh",
-            "version": "v0.12.3",
+            "version": "v0.12.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/bobthecow/psysh.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/bobthecow/psysh.git",
-                "reference": "b6b6cce7d3ee8fbf31843edce5e8f5a72eff4a73"
+                "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/b6b6cce7d3ee8fbf31843edce5e8f5a72eff4a73",
-                "reference": "b6b6cce7d3ee8fbf31843edce5e8f5a72eff4a73",
+                "url": "https://api.github.com/repos/bobthecow/psysh/zipball/85057ceedee50c49d4f6ecaff73ee96adb3b3625",
+                "reference": "85057ceedee50c49d4f6ecaff73ee96adb3b3625",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             ],
             "type": "library",
             "extra": {
             ],
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "0.12.x-dev"
-                },
                 "bamarni-bin": {
                     "bin-links": false,
                     "forward-command": false
                 "bamarni-bin": {
                     "bin-links": false,
                     "forward-command": false
+                },
+                "branch-alias": {
+                    "dev-main": "0.12.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/bobthecow/psysh/issues",
             ],
             "support": {
                 "issues": "https://github.com/bobthecow/psysh/issues",
-                "source": "https://github.com/bobthecow/psysh/tree/v0.12.3"
+                "source": "https://github.com/bobthecow/psysh/tree/v0.12.8"
             },
             },
-            "time": "2024-04-02T15:57:53+00:00"
+            "time": "2025-03-16T03:05:19+00:00"
         },
         {
             "name": "pusher/pusher-php-server",
         },
         {
             "name": "pusher/pusher-php-server",
-            "version": "7.2.4",
+            "version": "7.2.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/pusher/pusher-http-php.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/pusher/pusher-http-php.git",
-                "reference": "de2f72296808f9cafa6a4462b15a768ff130cddb"
+                "reference": "148b0b5100d000ed57195acdf548a2b1b38ee3f7"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/pusher/pusher-http-php/zipball/de2f72296808f9cafa6a4462b15a768ff130cddb",
-                "reference": "de2f72296808f9cafa6a4462b15a768ff130cddb",
+                "url": "https://api.github.com/repos/pusher/pusher-http-php/zipball/148b0b5100d000ed57195acdf548a2b1b38ee3f7",
+                "reference": "148b0b5100d000ed57195acdf548a2b1b38ee3f7",
                 "shasum": ""
             },
             "require": {
                 "ext-curl": "*",
                 "ext-json": "*",
                 "guzzlehttp/guzzle": "^7.2",
                 "shasum": ""
             },
             "require": {
                 "ext-curl": "*",
                 "ext-json": "*",
                 "guzzlehttp/guzzle": "^7.2",
-                "paragonie/sodium_compat": "^1.6",
+                "paragonie/sodium_compat": "^1.6|^2.0",
                 "php": "^7.3|^8.0",
                 "psr/log": "^1.0|^2.0|^3.0"
             },
                 "php": "^7.3|^8.0",
                 "psr/log": "^1.0|^2.0|^3.0"
             },
             ],
             "support": {
                 "issues": "https://github.com/pusher/pusher-http-php/issues",
             ],
             "support": {
                 "issues": "https://github.com/pusher/pusher-http-php/issues",
-                "source": "https://github.com/pusher/pusher-http-php/tree/7.2.4"
+                "source": "https://github.com/pusher/pusher-http-php/tree/7.2.7"
             },
             },
-            "time": "2023-12-15T10:58:53+00:00"
+            "time": "2025-01-06T10:56:20+00:00"
         },
         {
             "name": "ralouphie/getallheaders",
         },
         {
             "name": "ralouphie/getallheaders",
         },
         {
             "name": "ramsey/collection",
         },
         {
             "name": "ramsey/collection",
-            "version": "2.0.0",
+            "version": "2.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/collection.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/collection.git",
-                "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5"
+                "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ramsey/collection/zipball/a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
-                "reference": "a4b48764bfbb8f3a6a4d1aeb1a35bb5e9ecac4a5",
+                "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
+                "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "captainhook/plugin-composer": "^5.3",
             },
             "require-dev": {
                 "captainhook/plugin-composer": "^5.3",
-                "ergebnis/composer-normalize": "^2.28.3",
-                "fakerphp/faker": "^1.21",
+                "ergebnis/composer-normalize": "^2.45",
+                "fakerphp/faker": "^1.24",
                 "hamcrest/hamcrest-php": "^2.0",
                 "hamcrest/hamcrest-php": "^2.0",
-                "jangregor/phpstan-prophecy": "^1.0",
-                "mockery/mockery": "^1.5",
+                "jangregor/phpstan-prophecy": "^2.1",
+                "mockery/mockery": "^1.6",
                 "php-parallel-lint/php-console-highlighter": "^1.0",
                 "php-parallel-lint/php-console-highlighter": "^1.0",
-                "php-parallel-lint/php-parallel-lint": "^1.3",
-                "phpcsstandards/phpcsutils": "^1.0.0-rc1",
-                "phpspec/prophecy-phpunit": "^2.0",
-                "phpstan/extension-installer": "^1.2",
-                "phpstan/phpstan": "^1.9",
-                "phpstan/phpstan-mockery": "^1.1",
-                "phpstan/phpstan-phpunit": "^1.3",
-                "phpunit/phpunit": "^9.5",
-                "psalm/plugin-mockery": "^1.1",
-                "psalm/plugin-phpunit": "^0.18.4",
-                "ramsey/coding-standard": "^2.0.3",
-                "ramsey/conventional-commits": "^1.3",
-                "vimeo/psalm": "^5.4"
+                "php-parallel-lint/php-parallel-lint": "^1.4",
+                "phpspec/prophecy-phpunit": "^2.3",
+                "phpstan/extension-installer": "^1.4",
+                "phpstan/phpstan": "^2.1",
+                "phpstan/phpstan-mockery": "^2.0",
+                "phpstan/phpstan-phpunit": "^2.0",
+                "phpunit/phpunit": "^10.5",
+                "ramsey/coding-standard": "^2.3",
+                "ramsey/conventional-commits": "^1.6",
+                "roave/security-advisories": "dev-latest"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
             ],
             "support": {
                 "issues": "https://github.com/ramsey/collection/issues",
             ],
             "support": {
                 "issues": "https://github.com/ramsey/collection/issues",
-                "source": "https://github.com/ramsey/collection/tree/2.0.0"
+                "source": "https://github.com/ramsey/collection/tree/2.1.1"
             },
             },
-            "funding": [
-                {
-                    "url": "https://github.com/ramsey",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/ramsey/collection",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2022-12-31T21:50:55+00:00"
+            "time": "2025-03-22T05:38:12+00:00"
         },
         {
             "name": "ramsey/uuid",
         },
         {
             "name": "ramsey/uuid",
-            "version": "4.7.5",
+            "version": "4.8.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/uuid.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/uuid.git",
-                "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e"
+                "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e",
-                "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
+                "reference": "fdf4dd4e2ff1813111bd0ad58d7a1ddbb5b56c28",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11",
+                "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13",
                 "ext-json": "*",
                 "php": "^8.0",
                 "ramsey/collection": "^1.2 || ^2.0"
                 "ext-json": "*",
                 "php": "^8.0",
                 "ramsey/collection": "^1.2 || ^2.0"
                 "rhumsaa/uuid": "self.version"
             },
             "require-dev": {
                 "rhumsaa/uuid": "self.version"
             },
             "require-dev": {
-                "captainhook/captainhook": "^5.10",
+                "captainhook/captainhook": "^5.25",
                 "captainhook/plugin-composer": "^5.3",
                 "captainhook/plugin-composer": "^5.3",
-                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
-                "doctrine/annotations": "^1.8",
-                "ergebnis/composer-normalize": "^2.15",
-                "mockery/mockery": "^1.3",
+                "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
+                "ergebnis/composer-normalize": "^2.47",
+                "mockery/mockery": "^1.6",
                 "paragonie/random-lib": "^2",
                 "paragonie/random-lib": "^2",
-                "php-mock/php-mock": "^2.2",
-                "php-mock/php-mock-mockery": "^1.3",
-                "php-parallel-lint/php-parallel-lint": "^1.1",
-                "phpbench/phpbench": "^1.0",
-                "phpstan/extension-installer": "^1.1",
-                "phpstan/phpstan": "^1.8",
-                "phpstan/phpstan-mockery": "^1.1",
-                "phpstan/phpstan-phpunit": "^1.1",
-                "phpunit/phpunit": "^8.5 || ^9",
-                "ramsey/composer-repl": "^1.4",
-                "slevomat/coding-standard": "^8.4",
-                "squizlabs/php_codesniffer": "^3.5",
-                "vimeo/psalm": "^4.9"
+                "php-mock/php-mock": "^2.6",
+                "php-mock/php-mock-mockery": "^1.5",
+                "php-parallel-lint/php-parallel-lint": "^1.4.0",
+                "phpbench/phpbench": "^1.2.14",
+                "phpstan/extension-installer": "^1.4",
+                "phpstan/phpstan": "^2.1",
+                "phpstan/phpstan-mockery": "^2.0",
+                "phpstan/phpstan-phpunit": "^2.0",
+                "phpunit/phpunit": "^9.6",
+                "slevomat/coding-standard": "^8.18",
+                "squizlabs/php_codesniffer": "^3.13"
             },
             "suggest": {
                 "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
             },
             "suggest": {
                 "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
             ],
             "support": {
                 "issues": "https://github.com/ramsey/uuid/issues",
             ],
             "support": {
                 "issues": "https://github.com/ramsey/uuid/issues",
-                "source": "https://github.com/ramsey/uuid/tree/4.7.5"
+                "source": "https://github.com/ramsey/uuid/tree/4.8.1"
             },
             },
-            "funding": [
-                {
-                    "url": "https://github.com/ramsey",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2023-11-08T05:53:05+00:00"
+            "time": "2025-06-01T06:28:46+00:00"
         },
         {
             "name": "ratchet/pawl",
         },
         {
             "name": "ratchet/pawl",
-            "version": "v0.4.1",
+            "version": "v0.4.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ratchetphp/Pawl.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ratchetphp/Pawl.git",
-                "reference": "af70198bab77a582b31169d3cc3982bed25c161f"
+                "reference": "2c582373c78271de32cb04c755c4c0db7e09c9c0"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ratchetphp/Pawl/zipball/af70198bab77a582b31169d3cc3982bed25c161f",
-                "reference": "af70198bab77a582b31169d3cc3982bed25c161f",
+                "url": "https://api.github.com/repos/ratchetphp/Pawl/zipball/2c582373c78271de32cb04c755c4c0db7e09c9c0",
+                "reference": "2c582373c78271de32cb04c755c4c0db7e09c9c0",
                 "shasum": ""
             },
             "require": {
                 "evenement/evenement": "^3.0 || ^2.0",
                 "shasum": ""
             },
             "require": {
                 "evenement/evenement": "^3.0 || ^2.0",
-                "guzzlehttp/psr7": "^2.0 || ^1.7",
-                "php": ">=5.4",
-                "ratchet/rfc6455": "^0.3.1",
+                "guzzlehttp/psr7": "^2.0",
+                "php": ">=7.4",
+                "ratchet/rfc6455": "^0.3.1 || ^0.4.0",
                 "react/socket": "^1.9"
             },
             "require-dev": {
                 "react/socket": "^1.9"
             },
             "require-dev": {
             ],
             "support": {
                 "issues": "https://github.com/ratchetphp/Pawl/issues",
             ],
             "support": {
                 "issues": "https://github.com/ratchetphp/Pawl/issues",
-                "source": "https://github.com/ratchetphp/Pawl/tree/v0.4.1"
+                "source": "https://github.com/ratchetphp/Pawl/tree/v0.4.3"
             },
             },
-            "time": "2021-12-10T14:32:34+00:00"
+            "time": "2025-03-19T16:47:38+00:00"
         },
         {
             "name": "ratchet/rfc6455",
         },
         {
             "name": "ratchet/rfc6455",
-            "version": "v0.3.1",
+            "version": "v0.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ratchetphp/RFC6455.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ratchetphp/RFC6455.git",
-                "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb"
+                "reference": "859d95f85dda0912c6d5b936d036d044e3af47ef"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/7c964514e93456a52a99a20fcfa0de242a43ccdb",
-                "reference": "7c964514e93456a52a99a20fcfa0de242a43ccdb",
+                "url": "https://api.github.com/repos/ratchetphp/RFC6455/zipball/859d95f85dda0912c6d5b936d036d044e3af47ef",
+                "reference": "859d95f85dda0912c6d5b936d036d044e3af47ef",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "guzzlehttp/psr7": "^2 || ^1.7",
-                "php": ">=5.4.2"
+                "php": ">=7.4",
+                "psr/http-factory-implementation": "^1.0",
+                "symfony/polyfill-php80": "^1.15"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^5.7",
+                "guzzlehttp/psr7": "^2.7",
+                "phpunit/phpunit": "^9.5",
                 "react/socket": "^1.3"
             },
             "type": "library",
                 "react/socket": "^1.3"
             },
             "type": "library",
             "support": {
                 "chat": "https://gitter.im/reactphp/reactphp",
                 "issues": "https://github.com/ratchetphp/RFC6455/issues",
             "support": {
                 "chat": "https://gitter.im/reactphp/reactphp",
                 "issues": "https://github.com/ratchetphp/RFC6455/issues",
-                "source": "https://github.com/ratchetphp/RFC6455/tree/v0.3.1"
+                "source": "https://github.com/ratchetphp/RFC6455/tree/v0.4.0"
             },
             },
-            "time": "2021-12-09T23:20:49+00:00"
+            "time": "2025-02-24T01:18:22+00:00"
         },
         {
             "name": "react/cache",
         },
         {
             "name": "react/cache",
         },
         {
             "name": "react/child-process",
         },
         {
             "name": "react/child-process",
-            "version": "v0.6.5",
+            "version": "v0.6.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/child-process.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/child-process.git",
-                "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43"
+                "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/reactphp/child-process/zipball/e71eb1aa55f057c7a4a0d08d06b0b0a484bead43",
-                "reference": "e71eb1aa55f057c7a4a0d08d06b0b0a484bead43",
+                "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159",
+                "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159",
                 "shasum": ""
             },
             "require": {
                 "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
                 "php": ">=5.3.0",
                 "react/event-loop": "^1.2",
                 "shasum": ""
             },
             "require": {
                 "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
                 "php": ">=5.3.0",
                 "react/event-loop": "^1.2",
-                "react/stream": "^1.2"
+                "react/stream": "^1.4"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
-                "react/socket": "^1.8",
+                "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
+                "react/socket": "^1.16",
                 "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
                 "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0"
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
-                    "React\\ChildProcess\\": "src"
+                    "React\\ChildProcess\\": "src/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
             ],
             "support": {
                 "issues": "https://github.com/reactphp/child-process/issues",
             ],
             "support": {
                 "issues": "https://github.com/reactphp/child-process/issues",
-                "source": "https://github.com/reactphp/child-process/tree/v0.6.5"
+                "source": "https://github.com/reactphp/child-process/tree/v0.6.6"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
-                    "url": "https://github.com/WyriHaximus",
-                    "type": "github"
-                },
-                {
-                    "url": "https://github.com/clue",
-                    "type": "github"
+                    "url": "https://opencollective.com/reactphp",
+                    "type": "open_collective"
                 }
             ],
                 }
             ],
-            "time": "2022-09-16T13:41:56+00:00"
+            "time": "2025-01-01T16:37:48+00:00"
         },
         {
             "name": "react/datagram",
         },
         {
             "name": "react/datagram",
         },
         {
             "name": "react/dns",
         },
         {
             "name": "react/dns",
-            "version": "v1.12.0",
+            "version": "v1.13.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/dns.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/dns.git",
-                "reference": "c134600642fa615b46b41237ef243daa65bb64ec"
+                "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/reactphp/dns/zipball/c134600642fa615b46b41237ef243daa65bb64ec",
-                "reference": "c134600642fa615b46b41237ef243daa65bb64ec",
+                "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5",
+                "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.0",
                 "react/cache": "^1.0 || ^0.6 || ^0.5",
                 "react/event-loop": "^1.2",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.0",
                 "react/cache": "^1.0 || ^0.6 || ^0.5",
                 "react/event-loop": "^1.2",
-                "react/promise": "^3.0 || ^2.7 || ^1.2.1"
+                "react/promise": "^3.2 || ^2.7 || ^1.2.1"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
-                "react/async": "^4 || ^3 || ^2",
-                "react/promise-timer": "^1.9"
+                "react/async": "^4.3 || ^3 || ^2",
+                "react/promise-timer": "^1.11"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/reactphp/dns/issues",
             ],
             "support": {
                 "issues": "https://github.com/reactphp/dns/issues",
-                "source": "https://github.com/reactphp/dns/tree/v1.12.0"
+                "source": "https://github.com/reactphp/dns/tree/v1.13.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "open_collective"
                 }
             ],
                     "type": "open_collective"
                 }
             ],
-            "time": "2023-11-29T12:41:06+00:00"
+            "time": "2024-06-13T14:18:03+00:00"
         },
         {
             "name": "react/event-loop",
         },
         {
             "name": "react/event-loop",
         },
         {
             "name": "react/http",
         },
         {
             "name": "react/http",
-            "version": "v1.10.0",
+            "version": "v1.11.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/http.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/http.git",
-                "reference": "8111281ee57f22b7194f5dba225e609ba7ce4d20"
+                "reference": "8db02de41dcca82037367f67a2d4be365b1c4db9"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/reactphp/http/zipball/8111281ee57f22b7194f5dba225e609ba7ce4d20",
-                "reference": "8111281ee57f22b7194f5dba225e609ba7ce4d20",
+                "url": "https://api.github.com/repos/reactphp/http/zipball/8db02de41dcca82037367f67a2d4be365b1c4db9",
+                "reference": "8db02de41dcca82037367f67a2d4be365b1c4db9",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.0",
                 "psr/http-message": "^1.0",
                 "react/event-loop": "^1.2",
                 "php": ">=5.3.0",
                 "psr/http-message": "^1.0",
                 "react/event-loop": "^1.2",
-                "react/promise": "^3 || ^2.3 || ^1.2.1",
-                "react/socket": "^1.12",
-                "react/stream": "^1.2"
+                "react/promise": "^3.2 || ^2.3 || ^1.2.1",
+                "react/socket": "^1.16",
+                "react/stream": "^1.4"
             },
             "require-dev": {
                 "clue/http-proxy-react": "^1.8",
                 "clue/reactphp-ssh-proxy": "^1.4",
                 "clue/socks-react": "^1.4",
                 "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
             },
             "require-dev": {
                 "clue/http-proxy-react": "^1.8",
                 "clue/reactphp-ssh-proxy": "^1.4",
                 "clue/socks-react": "^1.4",
                 "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
-                "react/async": "^4 || ^3 || ^2",
+                "react/async": "^4.2 || ^3 || ^2",
                 "react/promise-stream": "^1.4",
                 "react/promise-stream": "^1.4",
-                "react/promise-timer": "^1.9"
+                "react/promise-timer": "^1.11"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/reactphp/http/issues",
             ],
             "support": {
                 "issues": "https://github.com/reactphp/http/issues",
-                "source": "https://github.com/reactphp/http/tree/v1.10.0"
+                "source": "https://github.com/reactphp/http/tree/v1.11.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "open_collective"
                 }
             ],
                     "type": "open_collective"
                 }
             ],
-            "time": "2024-03-27T17:20:46+00:00"
+            "time": "2024-11-20T15:24:08+00:00"
         },
         {
             "name": "react/partial",
         },
         {
             "name": "react/partial",
             ],
             "time": "2023-11-16T16:16:50+00:00"
         },
             ],
             "time": "2023-11-16T16:16:50+00:00"
         },
+        {
+            "name": "react/promise-timer",
+            "version": "v1.11.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/reactphp/promise-timer.git",
+                "reference": "4f70306ed66b8b44768941ca7f142092600fafc1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/reactphp/promise-timer/zipball/4f70306ed66b8b44768941ca7f142092600fafc1",
+                "reference": "4f70306ed66b8b44768941ca7f142092600fafc1",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3",
+                "react/event-loop": "^1.2",
+                "react/promise": "^3.2 || ^2.7.0 || ^1.2.1"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "src/functions_include.php"
+                ],
+                "psr-4": {
+                    "React\\Promise\\Timer\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Christian Lück",
+                    "email": "christian@clue.engineering",
+                    "homepage": "https://clue.engineering/"
+                },
+                {
+                    "name": "Cees-Jan Kiewiet",
+                    "email": "reactphp@ceesjankiewiet.nl",
+                    "homepage": "https://wyrihaximus.net/"
+                },
+                {
+                    "name": "Jan Sorgalla",
+                    "email": "jsorgalla@gmail.com",
+                    "homepage": "https://sorgalla.com/"
+                },
+                {
+                    "name": "Chris Boden",
+                    "email": "cboden@gmail.com",
+                    "homepage": "https://cboden.dev/"
+                }
+            ],
+            "description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
+            "homepage": "https://github.com/reactphp/promise-timer",
+            "keywords": [
+                "async",
+                "event-loop",
+                "promise",
+                "reactphp",
+                "timeout",
+                "timer"
+            ],
+            "support": {
+                "issues": "https://github.com/reactphp/promise-timer/issues",
+                "source": "https://github.com/reactphp/promise-timer/tree/v1.11.0"
+            },
+            "funding": [
+                {
+                    "url": "https://opencollective.com/reactphp",
+                    "type": "open_collective"
+                }
+            ],
+            "time": "2024-06-04T14:27:45+00:00"
+        },
         {
             "name": "react/socket",
         {
             "name": "react/socket",
-            "version": "v1.15.0",
+            "version": "v1.16.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/socket.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/socket.git",
-                "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038"
+                "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/reactphp/socket/zipball/216d3aec0b87f04a40ca04f481e6af01bdd1d038",
-                "reference": "216d3aec0b87f04a40ca04f481e6af01bdd1d038",
+                "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1",
+                "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1",
                 "shasum": ""
             },
             "require": {
                 "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
                 "php": ">=5.3.0",
                 "shasum": ""
             },
             "require": {
                 "evenement/evenement": "^3.0 || ^2.0 || ^1.0",
                 "php": ">=5.3.0",
-                "react/dns": "^1.11",
+                "react/dns": "^1.13",
                 "react/event-loop": "^1.2",
                 "react/event-loop": "^1.2",
-                "react/promise": "^3 || ^2.6 || ^1.2.1",
-                "react/stream": "^1.2"
+                "react/promise": "^3.2 || ^2.6 || ^1.2.1",
+                "react/stream": "^1.4"
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
             },
             "require-dev": {
                 "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36",
-                "react/async": "^4 || ^3 || ^2",
+                "react/async": "^4.3 || ^3.3 || ^2",
                 "react/promise-stream": "^1.4",
                 "react/promise-stream": "^1.4",
-                "react/promise-timer": "^1.10"
+                "react/promise-timer": "^1.11"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/reactphp/socket/issues",
             ],
             "support": {
                 "issues": "https://github.com/reactphp/socket/issues",
-                "source": "https://github.com/reactphp/socket/tree/v1.15.0"
+                "source": "https://github.com/reactphp/socket/tree/v1.16.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "open_collective"
                 }
             ],
                     "type": "open_collective"
                 }
             ],
-            "time": "2023-12-15T11:02:10+00:00"
+            "time": "2024-07-26T10:38:09+00:00"
         },
         {
             "name": "react/stream",
         },
         {
             "name": "react/stream",
-            "version": "v1.3.0",
+            "version": "v1.4.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/stream.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/reactphp/stream.git",
-                "reference": "6fbc9672905c7d5a885f2da2fc696f65840f4a66"
+                "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/reactphp/stream/zipball/6fbc9672905c7d5a885f2da2fc696f65840f4a66",
-                "reference": "6fbc9672905c7d5a885f2da2fc696f65840f4a66",
+                "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d",
+                "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "clue/stream-filter": "~1.2",
             },
             "require-dev": {
                 "clue/stream-filter": "~1.2",
-                "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35"
+                "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/reactphp/stream/issues",
             ],
             "support": {
                 "issues": "https://github.com/reactphp/stream/issues",
-                "source": "https://github.com/reactphp/stream/tree/v1.3.0"
+                "source": "https://github.com/reactphp/stream/tree/v1.4.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "open_collective"
                 }
             ],
                     "type": "open_collective"
                 }
             ],
-            "time": "2023-06-16T10:52:11+00:00"
+            "time": "2024-06-11T12:45:25+00:00"
         },
         {
             "name": "symfony/console",
         },
         {
             "name": "symfony/console",
-            "version": "v6.4.6",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/console.git",
-                "reference": "a2708a5da5c87d1d0d52937bdeac625df659e11f"
+                "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/a2708a5da5c87d1d0d52937bdeac625df659e11f",
-                "reference": "a2708a5da5c87d1d0d52937bdeac625df659e11f",
+                "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44",
+                "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
+                "php": ">=8.2",
                 "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/polyfill-mbstring": "~1.0",
                 "symfony/service-contracts": "^2.5|^3",
                 "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/polyfill-mbstring": "~1.0",
                 "symfony/service-contracts": "^2.5|^3",
-                "symfony/string": "^5.4|^6.0|^7.0"
+                "symfony/string": "^7.2"
             },
             "conflict": {
             },
             "conflict": {
-                "symfony/dependency-injection": "<5.4",
-                "symfony/dotenv": "<5.4",
-                "symfony/event-dispatcher": "<5.4",
-                "symfony/lock": "<5.4",
-                "symfony/process": "<5.4"
+                "symfony/dependency-injection": "<6.4",
+                "symfony/dotenv": "<6.4",
+                "symfony/event-dispatcher": "<6.4",
+                "symfony/lock": "<6.4",
+                "symfony/process": "<6.4"
             },
             "provide": {
                 "psr/log-implementation": "1.0|2.0|3.0"
             },
             "require-dev": {
                 "psr/log": "^1|^2|^3",
             },
             "provide": {
                 "psr/log-implementation": "1.0|2.0|3.0"
             },
             "require-dev": {
                 "psr/log": "^1|^2|^3",
-                "symfony/config": "^5.4|^6.0|^7.0",
-                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
-                "symfony/event-dispatcher": "^5.4|^6.0|^7.0",
+                "symfony/config": "^6.4|^7.0",
+                "symfony/dependency-injection": "^6.4|^7.0",
+                "symfony/event-dispatcher": "^6.4|^7.0",
                 "symfony/http-foundation": "^6.4|^7.0",
                 "symfony/http-kernel": "^6.4|^7.0",
                 "symfony/http-foundation": "^6.4|^7.0",
                 "symfony/http-kernel": "^6.4|^7.0",
-                "symfony/lock": "^5.4|^6.0|^7.0",
-                "symfony/messenger": "^5.4|^6.0|^7.0",
-                "symfony/process": "^5.4|^6.0|^7.0",
-                "symfony/stopwatch": "^5.4|^6.0|^7.0",
-                "symfony/var-dumper": "^5.4|^6.0|^7.0"
+                "symfony/lock": "^6.4|^7.0",
+                "symfony/messenger": "^6.4|^7.0",
+                "symfony/process": "^6.4|^7.0",
+                "symfony/stopwatch": "^6.4|^7.0",
+                "symfony/var-dumper": "^6.4|^7.0"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
                 "terminal"
             ],
             "support": {
                 "terminal"
             ],
             "support": {
-                "source": "https://github.com/symfony/console/tree/v6.4.6"
+                "source": "https://github.com/symfony/console/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-03-29T19:07:53+00:00"
+            "time": "2025-05-24T10:34:04+00:00"
         },
         {
             "name": "symfony/css-selector",
         },
         {
             "name": "symfony/css-selector",
-            "version": "v7.0.3",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/css-selector.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/css-selector.git",
-                "reference": "ec60a4edf94e63b0556b6a0888548bb400a3a3be"
+                "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/css-selector/zipball/ec60a4edf94e63b0556b6a0888548bb400a3a3be",
-                "reference": "ec60a4edf94e63b0556b6a0888548bb400a3a3be",
+                "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2",
+                "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             "description": "Converts CSS selectors to XPath expressions",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Converts CSS selectors to XPath expressions",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/css-selector/tree/v7.0.3"
+                "source": "https://github.com/symfony/css-selector/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-23T15:02:46+00:00"
+            "time": "2024-09-25T14:21:43+00:00"
         },
         {
             "name": "symfony/deprecation-contracts",
         },
         {
             "name": "symfony/deprecation-contracts",
-            "version": "v3.4.0",
+            "version": "v3.6.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/deprecation-contracts.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/deprecation-contracts.git",
-                "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf"
+                "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf",
-                "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf",
+                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+                "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "3.4-dev"
-                },
                 "thanks": {
                 "thanks": {
-                    "name": "symfony/contracts",
-                    "url": "https://github.com/symfony/contracts"
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
+                "branch-alias": {
+                    "dev-main": "3.6-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "description": "A generic function and convention to trigger deprecation notices",
             "homepage": "https://symfony.com",
             "support": {
             "description": "A generic function and convention to trigger deprecation notices",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0"
+                "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-05-23T14:45:45+00:00"
+            "time": "2024-09-25T14:21:43+00:00"
         },
         {
             "name": "symfony/error-handler",
         },
         {
             "name": "symfony/error-handler",
-            "version": "v6.4.6",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/error-handler.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/error-handler.git",
-                "reference": "64db1c1802e3a4557e37ba33031ac39f452ac5d4"
+                "reference": "cf68d225bc43629de4ff54778029aee6dc191b83"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/error-handler/zipball/64db1c1802e3a4557e37ba33031ac39f452ac5d4",
-                "reference": "64db1c1802e3a4557e37ba33031ac39f452ac5d4",
+                "url": "https://api.github.com/repos/symfony/error-handler/zipball/cf68d225bc43629de4ff54778029aee6dc191b83",
+                "reference": "cf68d225bc43629de4ff54778029aee6dc191b83",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
+                "php": ">=8.2",
                 "psr/log": "^1|^2|^3",
                 "psr/log": "^1|^2|^3",
-                "symfony/var-dumper": "^5.4|^6.0|^7.0"
+                "symfony/var-dumper": "^6.4|^7.0"
             },
             "conflict": {
                 "symfony/deprecation-contracts": "<2.5",
                 "symfony/http-kernel": "<6.4"
             },
             "require-dev": {
             },
             "conflict": {
                 "symfony/deprecation-contracts": "<2.5",
                 "symfony/http-kernel": "<6.4"
             },
             "require-dev": {
+                "symfony/console": "^6.4|^7.0",
                 "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/http-kernel": "^6.4|^7.0",
                 "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/http-kernel": "^6.4|^7.0",
-                "symfony/serializer": "^5.4|^6.0|^7.0"
+                "symfony/serializer": "^6.4|^7.0",
+                "symfony/webpack-encore-bundle": "^1.0|^2.0"
             },
             "bin": [
                 "Resources/bin/patch-type-declarations"
             },
             "bin": [
                 "Resources/bin/patch-type-declarations"
             "description": "Provides tools to manage errors and ease debugging PHP code",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Provides tools to manage errors and ease debugging PHP code",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/error-handler/tree/v6.4.6"
+                "source": "https://github.com/symfony/error-handler/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-03-19T11:56:30+00:00"
+            "time": "2025-05-29T07:19:49+00:00"
         },
         {
             "name": "symfony/event-dispatcher",
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v7.0.3",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "834c28d533dd0636f910909d01b9ff45cc094b5e"
+                "reference": "497f73ac996a598c92409b44ac43b6690c4f666d"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/834c28d533dd0636f910909d01b9ff45cc094b5e",
-                "reference": "834c28d533dd0636f910909d01b9ff45cc094b5e",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d",
+                "reference": "497f73ac996a598c92409b44ac43b6690c4f666d",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/event-dispatcher/tree/v7.0.3"
+                "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-23T15:02:46+00:00"
+            "time": "2025-04-22T09:11:45+00:00"
         },
         {
             "name": "symfony/event-dispatcher-contracts",
         },
         {
             "name": "symfony/event-dispatcher-contracts",
-            "version": "v3.4.2",
+            "version": "v3.6.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher-contracts.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher-contracts.git",
-                "reference": "4e64b49bf370ade88e567de29465762e316e4224"
+                "reference": "59eb412e93815df44f05f342958efa9f46b1e586"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/4e64b49bf370ade88e567de29465762e316e4224",
-                "reference": "4e64b49bf370ade88e567de29465762e316e4224",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586",
+                "reference": "59eb412e93815df44f05f342958efa9f46b1e586",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "3.4-dev"
-                },
                 "thanks": {
                 "thanks": {
-                    "name": "symfony/contracts",
-                    "url": "https://github.com/symfony/contracts"
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
+                "branch-alias": {
+                    "dev-main": "3.6-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "standards"
             ],
             "support": {
                 "standards"
             ],
             "support": {
-                "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.2"
+                "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-23T14:51:35+00:00"
+            "time": "2024-09-25T14:21:43+00:00"
         },
         {
             "name": "symfony/finder",
         },
         {
             "name": "symfony/finder",
-            "version": "v6.4.0",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "11d736e97f116ac375a81f96e662911a34cd50ce"
+                "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/11d736e97f116ac375a81f96e662911a34cd50ce",
-                "reference": "11d736e97f116ac375a81f96e662911a34cd50ce",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d",
+                "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "symfony/filesystem": "^6.0|^7.0"
+                "symfony/filesystem": "^6.4|^7.0"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             "description": "Finds files and directories via an intuitive fluent interface",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Finds files and directories via an intuitive fluent interface",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/finder/tree/v6.4.0"
+                "source": "https://github.com/symfony/finder/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-10-31T17:30:12+00:00"
+            "time": "2024-12-30T19:00:26+00:00"
         },
         {
             "name": "symfony/http-foundation",
         },
         {
             "name": "symfony/http-foundation",
-            "version": "v6.4.4",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-foundation.git",
-                "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304"
+                "reference": "4236baf01609667d53b20371486228231eb135fd"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304",
-                "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304",
+                "url": "https://api.github.com/repos/symfony/http-foundation/zipball/4236baf01609667d53b20371486228231eb135fd",
+                "reference": "4236baf01609667d53b20371486228231eb135fd",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
-                "symfony/deprecation-contracts": "^2.5|^3",
+                "php": ">=8.2",
+                "symfony/deprecation-contracts": "^2.5|^3.0",
                 "symfony/polyfill-mbstring": "~1.1",
                 "symfony/polyfill-php83": "^1.27"
             },
             "conflict": {
                 "symfony/polyfill-mbstring": "~1.1",
                 "symfony/polyfill-php83": "^1.27"
             },
             "conflict": {
-                "symfony/cache": "<6.3"
+                "doctrine/dbal": "<3.6",
+                "symfony/cache": "<6.4.12|>=7.0,<7.1.5"
             },
             "require-dev": {
             },
             "require-dev": {
-                "doctrine/dbal": "^2.13.1|^3|^4",
+                "doctrine/dbal": "^3.6|^4",
                 "predis/predis": "^1.1|^2.0",
                 "predis/predis": "^1.1|^2.0",
-                "symfony/cache": "^6.3|^7.0",
-                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
-                "symfony/expression-language": "^5.4|^6.0|^7.0",
-                "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0",
-                "symfony/mime": "^5.4|^6.0|^7.0",
-                "symfony/rate-limiter": "^5.4|^6.0|^7.0"
+                "symfony/cache": "^6.4.12|^7.1.5",
+                "symfony/clock": "^6.4|^7.0",
+                "symfony/dependency-injection": "^6.4|^7.0",
+                "symfony/expression-language": "^6.4|^7.0",
+                "symfony/http-kernel": "^6.4|^7.0",
+                "symfony/mime": "^6.4|^7.0",
+                "symfony/rate-limiter": "^6.4|^7.0"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             "description": "Defines an object-oriented layer for the HTTP specification",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Defines an object-oriented layer for the HTTP specification",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-foundation/tree/v6.4.4"
+                "source": "https://github.com/symfony/http-foundation/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-02-08T15:01:18+00:00"
+            "time": "2025-05-12T14:48:23+00:00"
         },
         {
             "name": "symfony/http-kernel",
         },
         {
             "name": "symfony/http-kernel",
-            "version": "v6.4.6",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-kernel.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/http-kernel.git",
-                "reference": "060038863743fd0cd982be06acecccf246d35653"
+                "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/060038863743fd0cd982be06acecccf246d35653",
-                "reference": "060038863743fd0cd982be06acecccf246d35653",
+                "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ac7b8e163e8c83dce3abcc055a502d4486051a9f",
+                "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
+                "php": ">=8.2",
                 "psr/log": "^1|^2|^3",
                 "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/error-handler": "^6.4|^7.0",
                 "psr/log": "^1|^2|^3",
                 "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/error-handler": "^6.4|^7.0",
-                "symfony/event-dispatcher": "^5.4|^6.0|^7.0",
-                "symfony/http-foundation": "^6.4|^7.0",
+                "symfony/event-dispatcher": "^7.3",
+                "symfony/http-foundation": "^7.3",
                 "symfony/polyfill-ctype": "^1.8"
             },
             "conflict": {
                 "symfony/polyfill-ctype": "^1.8"
             },
             "conflict": {
-                "symfony/browser-kit": "<5.4",
-                "symfony/cache": "<5.4",
-                "symfony/config": "<6.1",
-                "symfony/console": "<5.4",
+                "symfony/browser-kit": "<6.4",
+                "symfony/cache": "<6.4",
+                "symfony/config": "<6.4",
+                "symfony/console": "<6.4",
                 "symfony/dependency-injection": "<6.4",
                 "symfony/dependency-injection": "<6.4",
-                "symfony/doctrine-bridge": "<5.4",
-                "symfony/form": "<5.4",
-                "symfony/http-client": "<5.4",
+                "symfony/doctrine-bridge": "<6.4",
+                "symfony/form": "<6.4",
+                "symfony/http-client": "<6.4",
                 "symfony/http-client-contracts": "<2.5",
                 "symfony/http-client-contracts": "<2.5",
-                "symfony/mailer": "<5.4",
-                "symfony/messenger": "<5.4",
-                "symfony/translation": "<5.4",
+                "symfony/mailer": "<6.4",
+                "symfony/messenger": "<6.4",
+                "symfony/translation": "<6.4",
                 "symfony/translation-contracts": "<2.5",
                 "symfony/translation-contracts": "<2.5",
-                "symfony/twig-bridge": "<5.4",
+                "symfony/twig-bridge": "<6.4",
                 "symfony/validator": "<6.4",
                 "symfony/validator": "<6.4",
-                "symfony/var-dumper": "<6.3",
-                "twig/twig": "<2.13"
+                "symfony/var-dumper": "<6.4",
+                "twig/twig": "<3.12"
             },
             "provide": {
                 "psr/log-implementation": "1.0|2.0|3.0"
             },
             "require-dev": {
                 "psr/cache": "^1.0|^2.0|^3.0",
             },
             "provide": {
                 "psr/log-implementation": "1.0|2.0|3.0"
             },
             "require-dev": {
                 "psr/cache": "^1.0|^2.0|^3.0",
-                "symfony/browser-kit": "^5.4|^6.0|^7.0",
-                "symfony/clock": "^6.2|^7.0",
-                "symfony/config": "^6.1|^7.0",
-                "symfony/console": "^5.4|^6.0|^7.0",
-                "symfony/css-selector": "^5.4|^6.0|^7.0",
+                "symfony/browser-kit": "^6.4|^7.0",
+                "symfony/clock": "^6.4|^7.0",
+                "symfony/config": "^6.4|^7.0",
+                "symfony/console": "^6.4|^7.0",
+                "symfony/css-selector": "^6.4|^7.0",
                 "symfony/dependency-injection": "^6.4|^7.0",
                 "symfony/dependency-injection": "^6.4|^7.0",
-                "symfony/dom-crawler": "^5.4|^6.0|^7.0",
-                "symfony/expression-language": "^5.4|^6.0|^7.0",
-                "symfony/finder": "^5.4|^6.0|^7.0",
+                "symfony/dom-crawler": "^6.4|^7.0",
+                "symfony/expression-language": "^6.4|^7.0",
+                "symfony/finder": "^6.4|^7.0",
                 "symfony/http-client-contracts": "^2.5|^3",
                 "symfony/http-client-contracts": "^2.5|^3",
-                "symfony/process": "^5.4|^6.0|^7.0",
-                "symfony/property-access": "^5.4.5|^6.0.5|^7.0",
-                "symfony/routing": "^5.4|^6.0|^7.0",
-                "symfony/serializer": "^6.4.4|^7.0.4",
-                "symfony/stopwatch": "^5.4|^6.0|^7.0",
-                "symfony/translation": "^5.4|^6.0|^7.0",
+                "symfony/process": "^6.4|^7.0",
+                "symfony/property-access": "^7.1",
+                "symfony/routing": "^6.4|^7.0",
+                "symfony/serializer": "^7.1",
+                "symfony/stopwatch": "^6.4|^7.0",
+                "symfony/translation": "^6.4|^7.0",
                 "symfony/translation-contracts": "^2.5|^3",
                 "symfony/translation-contracts": "^2.5|^3",
-                "symfony/uid": "^5.4|^6.0|^7.0",
+                "symfony/uid": "^6.4|^7.0",
                 "symfony/validator": "^6.4|^7.0",
                 "symfony/validator": "^6.4|^7.0",
-                "symfony/var-exporter": "^6.2|^7.0",
-                "twig/twig": "^2.13|^3.0.4"
+                "symfony/var-dumper": "^6.4|^7.0",
+                "symfony/var-exporter": "^6.4|^7.0",
+                "twig/twig": "^3.12"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             "description": "Provides a structured process for converting a Request into a Response",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Provides a structured process for converting a Request into a Response",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/http-kernel/tree/v6.4.6"
+                "source": "https://github.com/symfony/http-kernel/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-04-03T06:09:15+00:00"
+            "time": "2025-05-29T07:47:32+00:00"
         },
         {
             "name": "symfony/mailer",
         },
         {
             "name": "symfony/mailer",
-            "version": "v6.4.6",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/mailer.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/mailer.git",
-                "reference": "677f34a6f4b4559e08acf73ae0aec460479e5859"
+                "reference": "0f375bbbde96ae8c78e4aa3e63aabd486e33364c"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/mailer/zipball/677f34a6f4b4559e08acf73ae0aec460479e5859",
-                "reference": "677f34a6f4b4559e08acf73ae0aec460479e5859",
+                "url": "https://api.github.com/repos/symfony/mailer/zipball/0f375bbbde96ae8c78e4aa3e63aabd486e33364c",
+                "reference": "0f375bbbde96ae8c78e4aa3e63aabd486e33364c",
                 "shasum": ""
             },
             "require": {
                 "egulias/email-validator": "^2.1.10|^3|^4",
                 "shasum": ""
             },
             "require": {
                 "egulias/email-validator": "^2.1.10|^3|^4",
-                "php": ">=8.1",
+                "php": ">=8.2",
                 "psr/event-dispatcher": "^1",
                 "psr/log": "^1|^2|^3",
                 "psr/event-dispatcher": "^1",
                 "psr/log": "^1|^2|^3",
-                "symfony/event-dispatcher": "^5.4|^6.0|^7.0",
-                "symfony/mime": "^6.2|^7.0",
+                "symfony/event-dispatcher": "^6.4|^7.0",
+                "symfony/mime": "^7.2",
                 "symfony/service-contracts": "^2.5|^3"
             },
             "conflict": {
                 "symfony/http-client-contracts": "<2.5",
                 "symfony/service-contracts": "^2.5|^3"
             },
             "conflict": {
                 "symfony/http-client-contracts": "<2.5",
-                "symfony/http-kernel": "<5.4",
-                "symfony/messenger": "<6.2",
-                "symfony/mime": "<6.2",
-                "symfony/twig-bridge": "<6.2.1"
+                "symfony/http-kernel": "<6.4",
+                "symfony/messenger": "<6.4",
+                "symfony/mime": "<6.4",
+                "symfony/twig-bridge": "<6.4"
             },
             "require-dev": {
             },
             "require-dev": {
-                "symfony/console": "^5.4|^6.0|^7.0",
-                "symfony/http-client": "^5.4|^6.0|^7.0",
-                "symfony/messenger": "^6.2|^7.0",
-                "symfony/twig-bridge": "^6.2|^7.0"
+                "symfony/console": "^6.4|^7.0",
+                "symfony/http-client": "^6.4|^7.0",
+                "symfony/messenger": "^6.4|^7.0",
+                "symfony/twig-bridge": "^6.4|^7.0"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             "description": "Helps sending emails",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Helps sending emails",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/mailer/tree/v6.4.6"
+                "source": "https://github.com/symfony/mailer/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-03-27T21:14:17+00:00"
+            "time": "2025-04-04T09:51:09+00:00"
         },
         {
             "name": "symfony/mime",
         },
         {
             "name": "symfony/mime",
-            "version": "v6.4.6",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/mime.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/mime.git",
-                "reference": "14762b86918823cb42e3558cdcca62e58b5227fe"
+                "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/mime/zipball/14762b86918823cb42e3558cdcca62e58b5227fe",
-                "reference": "14762b86918823cb42e3558cdcca62e58b5227fe",
+                "url": "https://api.github.com/repos/symfony/mime/zipball/0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9",
+                "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
-                "symfony/deprecation-contracts": "^2.5|^3",
+                "php": ">=8.2",
                 "symfony/polyfill-intl-idn": "^1.10",
                 "symfony/polyfill-mbstring": "^1.0"
             },
                 "symfony/polyfill-intl-idn": "^1.10",
                 "symfony/polyfill-mbstring": "^1.0"
             },
                 "egulias/email-validator": "~3.0.0",
                 "phpdocumentor/reflection-docblock": "<3.2.2",
                 "phpdocumentor/type-resolver": "<1.4.0",
                 "egulias/email-validator": "~3.0.0",
                 "phpdocumentor/reflection-docblock": "<3.2.2",
                 "phpdocumentor/type-resolver": "<1.4.0",
-                "symfony/mailer": "<5.4",
-                "symfony/serializer": "<6.3.2"
+                "symfony/mailer": "<6.4",
+                "symfony/serializer": "<6.4.3|>7.0,<7.0.3"
             },
             "require-dev": {
                 "egulias/email-validator": "^2.1.10|^3.1|^4",
                 "league/html-to-markdown": "^5.0",
                 "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
             },
             "require-dev": {
                 "egulias/email-validator": "^2.1.10|^3.1|^4",
                 "league/html-to-markdown": "^5.0",
                 "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
-                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
-                "symfony/process": "^5.4|^6.4|^7.0",
-                "symfony/property-access": "^5.4|^6.0|^7.0",
-                "symfony/property-info": "^5.4|^6.0|^7.0",
-                "symfony/serializer": "^6.3.2|^7.0"
+                "symfony/dependency-injection": "^6.4|^7.0",
+                "symfony/process": "^6.4|^7.0",
+                "symfony/property-access": "^6.4|^7.0",
+                "symfony/property-info": "^6.4|^7.0",
+                "symfony/serializer": "^6.4.3|^7.0.3"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
                 "mime-type"
             ],
             "support": {
                 "mime-type"
             ],
             "support": {
-                "source": "https://github.com/symfony/mime/tree/v6.4.6"
+                "source": "https://github.com/symfony/mime/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-03-21T19:36:20+00:00"
+            "time": "2025-02-19T08:51:26+00:00"
         },
         {
             "name": "symfony/options-resolver",
         },
         {
             "name": "symfony/options-resolver",
-            "version": "v6.4.0",
+            "version": "v6.4.16",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/options-resolver.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/options-resolver.git",
-                "reference": "22301f0e7fdeaacc14318928612dee79be99860e"
+                "reference": "368128ad168f20e22c32159b9f761e456cec0c78"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/options-resolver/zipball/22301f0e7fdeaacc14318928612dee79be99860e",
-                "reference": "22301f0e7fdeaacc14318928612dee79be99860e",
+                "url": "https://api.github.com/repos/symfony/options-resolver/zipball/368128ad168f20e22c32159b9f761e456cec0c78",
+                "reference": "368128ad168f20e22c32159b9f761e456cec0c78",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "options"
             ],
             "support": {
                 "options"
             ],
             "support": {
-                "source": "https://github.com/symfony/options-resolver/tree/v6.4.0"
+                "source": "https://github.com/symfony/options-resolver/tree/v6.4.16"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-08-08T10:16:24+00:00"
+            "time": "2024-11-20T10:57:02+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
         },
         {
             "name": "symfony/polyfill-ctype",
-            "version": "v1.29.0",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-ctype.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-ctype.git",
-                "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4"
+                "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4",
-                "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+                "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
             "provide": {
                 "ext-ctype": "*"
             },
             "provide": {
                 "ext-ctype": "*"
             "type": "library",
             "extra": {
                 "thanks": {
             "type": "library",
             "extra": {
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "portable"
             ],
             "support": {
                 "portable"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0"
+                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-29T20:11:03+00:00"
+            "time": "2024-09-09T11:45:10+00:00"
         },
         {
             "name": "symfony/polyfill-intl-grapheme",
         },
         {
             "name": "symfony/polyfill-intl-grapheme",
-            "version": "v1.29.0",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
-                "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f"
+                "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f",
-                "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f",
+                "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+                "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
             "suggest": {
                 "ext-intl": "For best performance"
             },
             "suggest": {
                 "ext-intl": "For best performance"
             "type": "library",
             "extra": {
                 "thanks": {
             "type": "library",
             "extra": {
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "shim"
             ],
             "support": {
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0"
+                "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-29T20:11:03+00:00"
+            "time": "2024-09-09T11:45:10+00:00"
         },
         {
             "name": "symfony/polyfill-intl-idn",
         },
         {
             "name": "symfony/polyfill-intl-idn",
-            "version": "v1.29.0",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-intl-idn.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-intl-idn.git",
-                "reference": "a287ed7475f85bf6f61890146edbc932c0fff919"
+                "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/a287ed7475f85bf6f61890146edbc932c0fff919",
-                "reference": "a287ed7475f85bf6f61890146edbc932c0fff919",
+                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3",
+                "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1",
-                "symfony/polyfill-intl-normalizer": "^1.10",
-                "symfony/polyfill-php72": "^1.10"
+                "php": ">=7.2",
+                "symfony/polyfill-intl-normalizer": "^1.10"
             },
             "suggest": {
                 "ext-intl": "For best performance"
             },
             "suggest": {
                 "ext-intl": "For best performance"
             "type": "library",
             "extra": {
                 "thanks": {
             "type": "library",
             "extra": {
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "shim"
             ],
             "support": {
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.29.0"
+                "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-29T20:11:03+00:00"
+            "time": "2024-09-10T14:38:51+00:00"
         },
         {
             "name": "symfony/polyfill-intl-normalizer",
         },
         {
             "name": "symfony/polyfill-intl-normalizer",
-            "version": "v1.29.0",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
-                "reference": "bc45c394692b948b4d383a08d7753968bed9a83d"
+                "reference": "3833d7255cc303546435cb650316bff708a1c75c"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d",
-                "reference": "bc45c394692b948b4d383a08d7753968bed9a83d",
+                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
+                "reference": "3833d7255cc303546435cb650316bff708a1c75c",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
             "suggest": {
                 "ext-intl": "For best performance"
             },
             "suggest": {
                 "ext-intl": "For best performance"
             "type": "library",
             "extra": {
                 "thanks": {
             "type": "library",
             "extra": {
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "shim"
             ],
             "support": {
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0"
+                "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-29T20:11:03+00:00"
+            "time": "2024-09-09T11:45:10+00:00"
         },
         {
             "name": "symfony/polyfill-mbstring",
         },
         {
             "name": "symfony/polyfill-mbstring",
-            "version": "v1.29.0",
+            "version": "v1.31.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec"
+                "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
-                "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
+                "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
             "provide": {
                 "ext-mbstring": "*"
             },
             "provide": {
                 "ext-mbstring": "*"
             "type": "library",
             "extra": {
                 "thanks": {
             "type": "library",
             "extra": {
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "shim"
             ],
             "support": {
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0"
-            },
-            "funding": [
-                {
-                    "url": "https://symfony.com/sponsor",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/fabpot",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2024-01-29T20:11:03+00:00"
-        },
-        {
-            "name": "symfony/polyfill-php72",
-            "version": "v1.29.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php72.git",
-                "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/861391a8da9a04cbad2d232ddd9e4893220d6e25",
-                "reference": "861391a8da9a04cbad2d232ddd9e4893220d6e25",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.1"
-            },
-            "type": "library",
-            "extra": {
-                "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
-                }
-            },
-            "autoload": {
-                "files": [
-                    "bootstrap.php"
-                ],
-                "psr-4": {
-                    "Symfony\\Polyfill\\Php72\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "support": {
-                "source": "https://github.com/symfony/polyfill-php72/tree/v1.29.0"
+                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-29T20:11:03+00:00"
+            "time": "2024-09-09T11:45:10+00:00"
         },
         {
             "name": "symfony/polyfill-php80",
         },
         {
             "name": "symfony/polyfill-php80",
-            "version": "v1.29.0",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php80.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php80.git",
-                "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
+                "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
-                "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
+                "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
             "type": "library",
             "extra": {
                 "thanks": {
             },
             "type": "library",
             "extra": {
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "shim"
             ],
             "support": {
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-29T20:11:03+00:00"
+            "time": "2025-01-02T08:10:11+00:00"
         },
         {
             "name": "symfony/polyfill-php83",
         },
         {
             "name": "symfony/polyfill-php83",
-            "version": "v1.29.0",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php83.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php83.git",
-                "reference": "86fcae159633351e5fd145d1c47de6c528f8caff"
+                "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff",
-                "reference": "86fcae159633351e5fd145d1c47de6c528f8caff",
+                "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491",
+                "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1",
-                "symfony/polyfill-php80": "^1.14"
+                "php": ">=7.2"
             },
             "type": "library",
             "extra": {
                 "thanks": {
             },
             "type": "library",
             "extra": {
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "shim"
             ],
             "support": {
                 "shim"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0"
+                "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-29T20:11:03+00:00"
+            "time": "2024-09-09T11:45:10+00:00"
         },
         {
             "name": "symfony/polyfill-uuid",
         },
         {
             "name": "symfony/polyfill-uuid",
-            "version": "v1.29.0",
+            "version": "v1.32.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-uuid.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-uuid.git",
-                "reference": "3abdd21b0ceaa3000ee950097bc3cf9efc137853"
+                "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/3abdd21b0ceaa3000ee950097bc3cf9efc137853",
-                "reference": "3abdd21b0ceaa3000ee950097bc3cf9efc137853",
+                "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2",
+                "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.1"
+                "php": ">=7.2"
             },
             "provide": {
                 "ext-uuid": "*"
             },
             "provide": {
                 "ext-uuid": "*"
             "type": "library",
             "extra": {
                 "thanks": {
             "type": "library",
             "extra": {
                 "thanks": {
-                    "name": "symfony/polyfill",
-                    "url": "https://github.com/symfony/polyfill"
+                    "url": "https://github.com/symfony/polyfill",
+                    "name": "symfony/polyfill"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "uuid"
             ],
             "support": {
                 "uuid"
             ],
             "support": {
-                "source": "https://github.com/symfony/polyfill-uuid/tree/v1.29.0"
+                "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-29T20:11:03+00:00"
+            "time": "2024-09-09T11:45:10+00:00"
         },
         {
             "name": "symfony/process",
         },
         {
             "name": "symfony/process",
-            "version": "v6.4.4",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "710e27879e9be3395de2b98da3f52a946039f297"
+                "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/710e27879e9be3395de2b98da3f52a946039f297",
-                "reference": "710e27879e9be3395de2b98da3f52a946039f297",
+                "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
+                "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1"
+                "php": ">=8.2"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
             "description": "Executes commands in sub-processes",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Executes commands in sub-processes",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/process/tree/v6.4.4"
-            },
-            "funding": [
-                {
-                    "url": "https://symfony.com/sponsor",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/fabpot",
-                    "type": "github"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
-                    "type": "tidelift"
-                }
-            ],
-            "time": "2024-02-20T12:31:00+00:00"
-        },
-        {
-            "name": "symfony/psr-http-message-bridge",
-            "version": "v2.3.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/psr-http-message-bridge.git",
-                "reference": "581ca6067eb62640de5ff08ee1ba6850a0ee472e"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/581ca6067eb62640de5ff08ee1ba6850a0ee472e",
-                "reference": "581ca6067eb62640de5ff08ee1ba6850a0ee472e",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=7.2.5",
-                "psr/http-message": "^1.0 || ^2.0",
-                "symfony/deprecation-contracts": "^2.5 || ^3.0",
-                "symfony/http-foundation": "^5.4 || ^6.0"
-            },
-            "require-dev": {
-                "nyholm/psr7": "^1.1",
-                "psr/log": "^1.1 || ^2 || ^3",
-                "symfony/browser-kit": "^5.4 || ^6.0",
-                "symfony/config": "^5.4 || ^6.0",
-                "symfony/event-dispatcher": "^5.4 || ^6.0",
-                "symfony/framework-bundle": "^5.4 || ^6.0",
-                "symfony/http-kernel": "^5.4 || ^6.0",
-                "symfony/phpunit-bridge": "^6.2"
-            },
-            "suggest": {
-                "nyholm/psr7": "For a super lightweight PSR-7/17 implementation"
-            },
-            "type": "symfony-bridge",
-            "extra": {
-                "branch-alias": {
-                    "dev-main": "2.3-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Bridge\\PsrHttpMessage\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "http://symfony.com/contributors"
-                }
-            ],
-            "description": "PSR HTTP message bridge",
-            "homepage": "http://symfony.com",
-            "keywords": [
-                "http",
-                "http-message",
-                "psr-17",
-                "psr-7"
-            ],
-            "support": {
-                "issues": "https://github.com/symfony/psr-http-message-bridge/issues",
-                "source": "https://github.com/symfony/psr-http-message-bridge/tree/v2.3.1"
+                "source": "https://github.com/symfony/process/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-07-26T11:53:26+00:00"
+            "time": "2025-04-17T09:11:12+00:00"
         },
         {
             "name": "symfony/routing",
         },
         {
             "name": "symfony/routing",
-            "version": "v6.4.6",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/routing.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/routing.git",
-                "reference": "f2591fd1f8c6e3734656b5d6b3829e8bf81f507c"
+                "reference": "8e213820c5fea844ecea29203d2a308019007c15"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/routing/zipball/f2591fd1f8c6e3734656b5d6b3829e8bf81f507c",
-                "reference": "f2591fd1f8c6e3734656b5d6b3829e8bf81f507c",
+                "url": "https://api.github.com/repos/symfony/routing/zipball/8e213820c5fea844ecea29203d2a308019007c15",
+                "reference": "8e213820c5fea844ecea29203d2a308019007c15",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
+                "php": ">=8.2",
                 "symfony/deprecation-contracts": "^2.5|^3"
             },
             "conflict": {
                 "symfony/deprecation-contracts": "^2.5|^3"
             },
             "conflict": {
-                "doctrine/annotations": "<1.12",
-                "symfony/config": "<6.2",
-                "symfony/dependency-injection": "<5.4",
-                "symfony/yaml": "<5.4"
+                "symfony/config": "<6.4",
+                "symfony/dependency-injection": "<6.4",
+                "symfony/yaml": "<6.4"
             },
             "require-dev": {
             },
             "require-dev": {
-                "doctrine/annotations": "^1.12|^2",
                 "psr/log": "^1|^2|^3",
                 "psr/log": "^1|^2|^3",
-                "symfony/config": "^6.2|^7.0",
-                "symfony/dependency-injection": "^5.4|^6.0|^7.0",
-                "symfony/expression-language": "^5.4|^6.0|^7.0",
-                "symfony/http-foundation": "^5.4|^6.0|^7.0",
-                "symfony/yaml": "^5.4|^6.0|^7.0"
+                "symfony/config": "^6.4|^7.0",
+                "symfony/dependency-injection": "^6.4|^7.0",
+                "symfony/expression-language": "^6.4|^7.0",
+                "symfony/http-foundation": "^6.4|^7.0",
+                "symfony/yaml": "^6.4|^7.0"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
                 "url"
             ],
             "support": {
                 "url"
             ],
             "support": {
-                "source": "https://github.com/symfony/routing/tree/v6.4.6"
+                "source": "https://github.com/symfony/routing/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-03-28T13:28:49+00:00"
+            "time": "2025-05-24T20:43:28+00:00"
         },
         {
             "name": "symfony/service-contracts",
         },
         {
             "name": "symfony/service-contracts",
-            "version": "v3.4.2",
+            "version": "v3.6.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/service-contracts.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/service-contracts.git",
-                "reference": "11bbf19a0fb7b36345861e85c5768844c552906e"
+                "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/service-contracts/zipball/11bbf19a0fb7b36345861e85c5768844c552906e",
-                "reference": "11bbf19a0fb7b36345861e85c5768844c552906e",
+                "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
+                "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4",
                 "shasum": ""
             },
             "require": {
                 "php": ">=8.1",
                 "shasum": ""
             },
             "require": {
                 "php": ">=8.1",
-                "psr/container": "^1.1|^2.0"
+                "psr/container": "^1.1|^2.0",
+                "symfony/deprecation-contracts": "^2.5|^3"
             },
             "conflict": {
                 "ext-psr": "<1.1|>=2"
             },
             "type": "library",
             "extra": {
             },
             "conflict": {
                 "ext-psr": "<1.1|>=2"
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "3.4-dev"
-                },
                 "thanks": {
                 "thanks": {
-                    "name": "symfony/contracts",
-                    "url": "https://github.com/symfony/contracts"
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
+                "branch-alias": {
+                    "dev-main": "3.6-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "standards"
             ],
             "support": {
                 "standards"
             ],
             "support": {
-                "source": "https://github.com/symfony/service-contracts/tree/v3.4.2"
+                "source": "https://github.com/symfony/service-contracts/tree/v3.6.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-19T21:51:00+00:00"
+            "time": "2025-04-25T09:37:31+00:00"
         },
         {
             "name": "symfony/string",
         },
         {
             "name": "symfony/string",
-            "version": "v7.0.4",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/string.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/string.git",
-                "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b"
+                "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/string/zipball/f5832521b998b0bec40bee688ad5de98d4cf111b",
-                "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b",
+                "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125",
+                "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "symfony/translation-contracts": "<2.5"
             },
             "require-dev": {
                 "symfony/translation-contracts": "<2.5"
             },
             "require-dev": {
+                "symfony/emoji": "^7.1",
                 "symfony/error-handler": "^6.4|^7.0",
                 "symfony/http-client": "^6.4|^7.0",
                 "symfony/intl": "^6.4|^7.0",
                 "symfony/error-handler": "^6.4|^7.0",
                 "symfony/http-client": "^6.4|^7.0",
                 "symfony/intl": "^6.4|^7.0",
                 "utf8"
             ],
             "support": {
                 "utf8"
             ],
             "support": {
-                "source": "https://github.com/symfony/string/tree/v7.0.4"
+                "source": "https://github.com/symfony/string/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-02-01T13:17:36+00:00"
+            "time": "2025-04-20T20:19:01+00:00"
         },
         {
             "name": "symfony/translation",
         },
         {
             "name": "symfony/translation",
-            "version": "v6.4.4",
+            "version": "v6.4.22",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation.git",
-                "reference": "bce6a5a78e94566641b2594d17e48b0da3184a8e"
+                "reference": "7e3b3b7146c6fab36ddff304a8041174bf6e17ad"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/translation/zipball/bce6a5a78e94566641b2594d17e48b0da3184a8e",
-                "reference": "bce6a5a78e94566641b2594d17e48b0da3184a8e",
+                "url": "https://api.github.com/repos/symfony/translation/zipball/7e3b3b7146c6fab36ddff304a8041174bf6e17ad",
+                "reference": "7e3b3b7146c6fab36ddff304a8041174bf6e17ad",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             "description": "Provides tools to internationalize your application",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Provides tools to internationalize your application",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/translation/tree/v6.4.4"
+                "source": "https://github.com/symfony/translation/tree/v6.4.22"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-02-20T13:16:58+00:00"
+            "time": "2025-05-29T07:06:44+00:00"
         },
         {
             "name": "symfony/translation-contracts",
         },
         {
             "name": "symfony/translation-contracts",
-            "version": "v3.4.2",
+            "version": "v3.6.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation-contracts.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/translation-contracts.git",
-                "reference": "43810bdb2ddb5400e5c5e778e27b210a0ca83b6b"
+                "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/43810bdb2ddb5400e5c5e778e27b210a0ca83b6b",
-                "reference": "43810bdb2ddb5400e5c5e778e27b210a0ca83b6b",
+                "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
+                "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-main": "3.4-dev"
-                },
                 "thanks": {
                 "thanks": {
-                    "name": "symfony/contracts",
-                    "url": "https://github.com/symfony/contracts"
+                    "url": "https://github.com/symfony/contracts",
+                    "name": "symfony/contracts"
+                },
+                "branch-alias": {
+                    "dev-main": "3.6-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 "standards"
             ],
             "support": {
                 "standards"
             ],
             "support": {
-                "source": "https://github.com/symfony/translation-contracts/tree/v3.4.2"
+                "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-23T14:51:35+00:00"
+            "time": "2024-09-27T08:32:26+00:00"
         },
         {
             "name": "symfony/uid",
         },
         {
             "name": "symfony/uid",
-            "version": "v6.4.3",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/uid.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/uid.git",
-                "reference": "1d31267211cc3a2fff32bcfc7c1818dac41b6fc0"
+                "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/uid/zipball/1d31267211cc3a2fff32bcfc7c1818dac41b6fc0",
-                "reference": "1d31267211cc3a2fff32bcfc7c1818dac41b6fc0",
+                "url": "https://api.github.com/repos/symfony/uid/zipball/7beeb2b885cd584cd01e126c5777206ae4c3c6a3",
+                "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
+                "php": ">=8.2",
                 "symfony/polyfill-uuid": "^1.15"
             },
             "require-dev": {
                 "symfony/polyfill-uuid": "^1.15"
             },
             "require-dev": {
-                "symfony/console": "^5.4|^6.0|^7.0"
+                "symfony/console": "^6.4|^7.0"
             },
             "type": "library",
             "autoload": {
             },
             "type": "library",
             "autoload": {
                 "uuid"
             ],
             "support": {
                 "uuid"
             ],
             "support": {
-                "source": "https://github.com/symfony/uid/tree/v6.4.3"
+                "source": "https://github.com/symfony/uid/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-23T14:51:35+00:00"
+            "time": "2025-05-24T14:28:13+00:00"
         },
         {
             "name": "symfony/var-dumper",
         },
         {
             "name": "symfony/var-dumper",
-            "version": "v6.4.6",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/var-dumper.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/var-dumper.git",
-                "reference": "95bd2706a97fb875185b51ecaa6112ec184233d4"
+                "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/95bd2706a97fb875185b51ecaa6112ec184233d4",
-                "reference": "95bd2706a97fb875185b51ecaa6112ec184233d4",
+                "url": "https://api.github.com/repos/symfony/var-dumper/zipball/548f6760c54197b1084e1e5c71f6d9d523f2f78e",
+                "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=8.1",
+                "php": ">=8.2",
                 "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/polyfill-mbstring": "~1.0"
             },
             "conflict": {
                 "symfony/deprecation-contracts": "^2.5|^3",
                 "symfony/polyfill-mbstring": "~1.0"
             },
             "conflict": {
-                "symfony/console": "<5.4"
+                "symfony/console": "<6.4"
             },
             "require-dev": {
                 "ext-iconv": "*",
             },
             "require-dev": {
                 "ext-iconv": "*",
-                "symfony/console": "^5.4|^6.0|^7.0",
-                "symfony/error-handler": "^6.3|^7.0",
-                "symfony/http-kernel": "^5.4|^6.0|^7.0",
-                "symfony/process": "^5.4|^6.0|^7.0",
-                "symfony/uid": "^5.4|^6.0|^7.0",
-                "twig/twig": "^2.13|^3.0.4"
+                "symfony/console": "^6.4|^7.0",
+                "symfony/http-kernel": "^6.4|^7.0",
+                "symfony/process": "^6.4|^7.0",
+                "symfony/uid": "^6.4|^7.0",
+                "twig/twig": "^3.12"
             },
             "bin": [
                 "Resources/bin/var-dump-server"
             },
             "bin": [
                 "Resources/bin/var-dump-server"
                 "dump"
             ],
             "support": {
                 "dump"
             ],
             "support": {
-                "source": "https://github.com/symfony/var-dumper/tree/v6.4.6"
+                "source": "https://github.com/symfony/var-dumper/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-03-19T11:56:30+00:00"
+            "time": "2025-04-27T18:39:23+00:00"
         },
         {
             "name": "team-reflex/discord-php",
         },
         {
             "name": "team-reflex/discord-php",
         },
         {
             "name": "tijsverkoyen/css-to-inline-styles",
         },
         {
             "name": "tijsverkoyen/css-to-inline-styles",
-            "version": "v2.2.7",
+            "version": "v2.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git",
-                "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb"
+                "reference": "0d72ac1c00084279c1816675284073c5a337c20d"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/83ee6f38df0a63106a9e4536e3060458b74ccedb",
-                "reference": "83ee6f38df0a63106a9e4536e3060458b74ccedb",
+                "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d",
+                "reference": "0d72ac1c00084279c1816675284073c5a337c20d",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
                 "ext-libxml": "*",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
                 "ext-libxml": "*",
-                "php": "^5.5 || ^7.0 || ^8.0",
-                "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0 || ^7.0"
+                "php": "^7.4 || ^8.0",
+                "symfony/css-selector": "^5.4 || ^6.0 || ^7.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10"
+                "phpstan/phpstan": "^2.0",
+                "phpstan/phpstan-phpunit": "^2.0",
+                "phpunit/phpunit": "^8.5.21 || ^9.5.10"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.2.x-dev"
+                    "dev-master": "2.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
             "support": {
                 "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues",
             "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles",
             "support": {
                 "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues",
-                "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.2.7"
+                "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0"
             },
             },
-            "time": "2023-12-08T13:03:43+00:00"
+            "time": "2024-12-21T16:25:41+00:00"
         },
         {
             "name": "trafficcophp/bytebuffer",
         },
         {
             "name": "trafficcophp/bytebuffer",
         },
         {
             "name": "vlucas/phpdotenv",
         },
         {
             "name": "vlucas/phpdotenv",
-            "version": "v5.6.0",
+            "version": "v5.6.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/vlucas/phpdotenv.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/vlucas/phpdotenv.git",
-                "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4"
+                "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4",
-                "reference": "2cf9fb6054c2bb1d59d1f3817706ecdb9d2934c4",
+                "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af",
+                "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af",
                 "shasum": ""
             },
             "require": {
                 "ext-pcre": "*",
                 "shasum": ""
             },
             "require": {
                 "ext-pcre": "*",
-                "graham-campbell/result-type": "^1.1.2",
+                "graham-campbell/result-type": "^1.1.3",
                 "php": "^7.2.5 || ^8.0",
                 "php": "^7.2.5 || ^8.0",
-                "phpoption/phpoption": "^1.9.2",
+                "phpoption/phpoption": "^1.9.3",
                 "symfony/polyfill-ctype": "^1.24",
                 "symfony/polyfill-mbstring": "^1.24",
                 "symfony/polyfill-php80": "^1.24"
                 "symfony/polyfill-ctype": "^1.24",
                 "symfony/polyfill-mbstring": "^1.24",
                 "symfony/polyfill-php80": "^1.24"
             "extra": {
                 "bamarni-bin": {
                     "bin-links": true,
             "extra": {
                 "bamarni-bin": {
                     "bin-links": true,
-                    "forward-command": true
+                    "forward-command": false
                 },
                 "branch-alias": {
                     "dev-master": "5.6-dev"
                 },
                 "branch-alias": {
                     "dev-master": "5.6-dev"
             ],
             "support": {
                 "issues": "https://github.com/vlucas/phpdotenv/issues",
             ],
             "support": {
                 "issues": "https://github.com/vlucas/phpdotenv/issues",
-                "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.0"
+                "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-11-12T22:43:29+00:00"
+            "time": "2025-04-30T23:37:27+00:00"
         },
         {
             "name": "voku/portable-ascii",
         },
         {
             "name": "voku/portable-ascii",
-            "version": "2.0.1",
+            "version": "2.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/voku/portable-ascii.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/voku/portable-ascii.git",
-                "reference": "b56450eed252f6801410d810c8e1727224ae0743"
+                "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b56450eed252f6801410d810c8e1727224ae0743",
-                "reference": "b56450eed252f6801410d810c8e1727224ae0743",
+                "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
+                "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             "authors": [
                 {
                     "name": "Lars Moelleken",
             "authors": [
                 {
                     "name": "Lars Moelleken",
-                    "homepage": "http://www.moelleken.org/"
+                    "homepage": "https://www.moelleken.org/"
                 }
             ],
             "description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
                 }
             ],
             "description": "Portable ASCII library - performance optimized (ascii) string functions for php.",
             ],
             "support": {
                 "issues": "https://github.com/voku/portable-ascii/issues",
             ],
             "support": {
                 "issues": "https://github.com/voku/portable-ascii/issues",
-                "source": "https://github.com/voku/portable-ascii/tree/2.0.1"
+                "source": "https://github.com/voku/portable-ascii/tree/2.0.3"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2022-03-08T17:03:00+00:00"
+            "time": "2024-11-21T01:49:47+00:00"
         },
         {
             "name": "webmozart/assert",
         },
         {
             "name": "webmozart/assert",
             ],
             "description": "Assertions to validate method input/output with nice error messages.",
             "keywords": [
             ],
             "description": "Assertions to validate method input/output with nice error messages.",
             "keywords": [
-                "assert",
-                "check",
-                "validate"
-            ],
-            "support": {
-                "issues": "https://github.com/webmozarts/assert/issues",
-                "source": "https://github.com/webmozarts/assert/tree/1.11.0"
-            },
-            "time": "2022-06-03T18:03:27+00:00"
-        },
-        {
-            "name": "z3/enemizer_linux",
-            "version": "6.1.0.180",
-            "dist": {
-                "type": "tar",
-                "url": "https://github.com/tcprescott/Enimizer/releases/download/2mb-rom/ubuntu.16.04-x64.tar.gz"
-            },
-            "type": "library"
-        }
-    ],
-    "packages-dev": [
-        {
-            "name": "doctrine/instantiator",
-            "version": "2.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
-                "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^8.1"
-            },
-            "require-dev": {
-                "doctrine/coding-standard": "^11",
-                "ext-pdo": "*",
-                "ext-phar": "*",
-                "phpbench/phpbench": "^1.2",
-                "phpstan/phpstan": "^1.9.4",
-                "phpstan/phpstan-phpunit": "^1.3",
-                "phpunit/phpunit": "^9.5.27",
-                "vimeo/psalm": "^5.4"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Marco Pivetta",
-                    "email": "ocramius@gmail.com",
-                    "homepage": "https://ocramius.github.io/"
-                }
-            ],
-            "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
-            "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
-            "keywords": [
-                "constructor",
-                "instantiate"
-            ],
-            "support": {
-                "issues": "https://github.com/doctrine/instantiator/issues",
-                "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
-            },
-            "funding": [
-                {
-                    "url": "https://www.doctrine-project.org/sponsorship.html",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://www.patreon.com/phpdoctrine",
-                    "type": "patreon"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
-                    "type": "tidelift"
-                }
+                "assert",
+                "check",
+                "validate"
             ],
             ],
-            "time": "2022-12-30T00:23:10+00:00"
+            "support": {
+                "issues": "https://github.com/webmozarts/assert/issues",
+                "source": "https://github.com/webmozarts/assert/tree/1.11.0"
+            },
+            "time": "2022-06-03T18:03:27+00:00"
         },
         },
+        {
+            "name": "z3/enemizer_linux",
+            "version": "6.1.0.180",
+            "dist": {
+                "type": "tar",
+                "url": "https://github.com/tcprescott/Enimizer/releases/download/2mb-rom/ubuntu.16.04-x64.tar.gz"
+            },
+            "type": "library"
+        }
+    ],
+    "packages-dev": [
         {
             "name": "fakerphp/faker",
         {
             "name": "fakerphp/faker",
-            "version": "v1.23.1",
+            "version": "v1.24.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/FakerPHP/Faker.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/FakerPHP/Faker.git",
-                "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b"
+                "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/bfb4fe148adbf78eff521199619b93a52ae3554b",
-                "reference": "bfb4fe148adbf78eff521199619b93a52ae3554b",
+                "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
+                "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/FakerPHP/Faker/issues",
             ],
             "support": {
                 "issues": "https://github.com/FakerPHP/Faker/issues",
-                "source": "https://github.com/FakerPHP/Faker/tree/v1.23.1"
+                "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1"
             },
             },
-            "time": "2024-01-02T13:46:09+00:00"
+            "time": "2024-11-21T13:46:39+00:00"
         },
         {
             "name": "filp/whoops",
         },
         {
             "name": "filp/whoops",
-            "version": "2.15.4",
+            "version": "2.18.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/filp/whoops.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/filp/whoops.git",
-                "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546"
+                "reference": "59a123a3d459c5a23055802237cb317f609867e5"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/filp/whoops/zipball/a139776fa3f5985a50b509f2a02ff0f709d2a546",
-                "reference": "a139776fa3f5985a50b509f2a02ff0f709d2a546",
+                "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5",
+                "reference": "59a123a3d459c5a23055802237cb317f609867e5",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": "^5.5.9 || ^7.0 || ^8.0",
+                "php": "^7.1 || ^8.0",
                 "psr/log": "^1.0.1 || ^2.0 || ^3.0"
             },
             "require-dev": {
                 "psr/log": "^1.0.1 || ^2.0 || ^3.0"
             },
             "require-dev": {
-                "mockery/mockery": "^0.9 || ^1.0",
-                "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3",
-                "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0"
+                "mockery/mockery": "^1.0",
+                "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3",
+                "symfony/var-dumper": "^4.0 || ^5.0"
             },
             "suggest": {
                 "symfony/var-dumper": "Pretty print complex values better with var-dumper available",
             },
             "suggest": {
                 "symfony/var-dumper": "Pretty print complex values better with var-dumper available",
             ],
             "support": {
                 "issues": "https://github.com/filp/whoops/issues",
             ],
             "support": {
                 "issues": "https://github.com/filp/whoops/issues",
-                "source": "https://github.com/filp/whoops/tree/2.15.4"
+                "source": "https://github.com/filp/whoops/tree/2.18.3"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-11-03T12:00:00+00:00"
+            "time": "2025-06-16T00:02:10+00:00"
         },
         {
             "name": "hamcrest/hamcrest-php",
         },
         {
             "name": "hamcrest/hamcrest-php",
-            "version": "v2.0.1",
+            "version": "v2.1.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/hamcrest/hamcrest-php.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/hamcrest/hamcrest-php.git",
-                "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3"
+                "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3",
-                "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3",
+                "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487",
+                "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": "^5.3|^7.0|^8.0"
+                "php": "^7.4|^8.0"
             },
             "replace": {
                 "cordoval/hamcrest-php": "*",
             },
             "replace": {
                 "cordoval/hamcrest-php": "*",
                 "kodova/hamcrest-php": "*"
             },
             "require-dev": {
                 "kodova/hamcrest-php": "*"
             },
             "require-dev": {
-                "phpunit/php-file-iterator": "^1.4 || ^2.0",
-                "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0"
+                "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0",
+                "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
             ],
             "support": {
                 "issues": "https://github.com/hamcrest/hamcrest-php/issues",
             ],
             "support": {
                 "issues": "https://github.com/hamcrest/hamcrest-php/issues",
-                "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1"
+                "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1"
             },
             },
-            "time": "2020-07-09T08:09:16+00:00"
+            "time": "2025-04-30T06:54:44+00:00"
         },
         {
             "name": "laravel/sail",
         },
         {
             "name": "laravel/sail",
-            "version": "v1.29.1",
+            "version": "v1.43.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/sail.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/sail.git",
-                "reference": "8be4a31150eab3b46af11a2e7b2c4632eefaad7e"
+                "reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/sail/zipball/8be4a31150eab3b46af11a2e7b2c4632eefaad7e",
-                "reference": "8be4a31150eab3b46af11a2e7b2c4632eefaad7e",
+                "url": "https://api.github.com/repos/laravel/sail/zipball/3e7d899232a8c5e3ea4fc6dee7525ad583887e72",
+                "reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "illuminate/console": "^9.52.16|^10.0|^11.0",
-                "illuminate/contracts": "^9.52.16|^10.0|^11.0",
-                "illuminate/support": "^9.52.16|^10.0|^11.0",
+                "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0",
+                "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0",
+                "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0",
                 "php": "^8.0",
                 "symfony/console": "^6.0|^7.0",
                 "symfony/yaml": "^6.0|^7.0"
             },
             "require-dev": {
                 "php": "^8.0",
                 "symfony/console": "^6.0|^7.0",
                 "symfony/yaml": "^6.0|^7.0"
             },
             "require-dev": {
-                "orchestra/testbench": "^7.0|^8.0|^9.0",
+                "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0",
                 "phpstan/phpstan": "^1.10"
             },
             "bin": [
                 "phpstan/phpstan": "^1.10"
             },
             "bin": [
                 "issues": "https://github.com/laravel/sail/issues",
                 "source": "https://github.com/laravel/sail"
             },
                 "issues": "https://github.com/laravel/sail/issues",
                 "source": "https://github.com/laravel/sail"
             },
-            "time": "2024-03-20T20:09:31+00:00"
+            "time": "2025-05-19T13:19:21+00:00"
         },
         {
             "name": "mockery/mockery",
         },
         {
             "name": "mockery/mockery",
-            "version": "1.6.11",
+            "version": "1.6.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/mockery/mockery.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/mockery/mockery.git",
-                "reference": "81a161d0b135df89951abd52296adf97deb0723d"
+                "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/mockery/mockery/zipball/81a161d0b135df89951abd52296adf97deb0723d",
-                "reference": "81a161d0b135df89951abd52296adf97deb0723d",
+                "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699",
+                "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
                 "security": "https://github.com/mockery/mockery/security/advisories",
                 "source": "https://github.com/mockery/mockery"
             },
                 "security": "https://github.com/mockery/mockery/security/advisories",
                 "source": "https://github.com/mockery/mockery"
             },
-            "time": "2024-03-21T18:34:15+00:00"
+            "time": "2024-05-16T03:13:13+00:00"
         },
         {
             "name": "myclabs/deep-copy",
         },
         {
             "name": "myclabs/deep-copy",
-            "version": "1.11.1",
+            "version": "1.13.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/DeepCopy.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/DeepCopy.git",
-                "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
+                "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
-                "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c",
+                "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
             },
             "conflict": {
                 "doctrine/collections": "<1.6.8",
             },
             "conflict": {
                 "doctrine/collections": "<1.6.8",
-                "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+                "doctrine/common": "<2.13.3 || >=3 <3.2.2"
             },
             "require-dev": {
                 "doctrine/collections": "^1.6.8",
                 "doctrine/common": "^2.13.3 || ^3.2.2",
             },
             "require-dev": {
                 "doctrine/collections": "^1.6.8",
                 "doctrine/common": "^2.13.3 || ^3.2.2",
+                "phpspec/prophecy": "^1.10",
                 "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
             },
             "type": "library",
                 "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
             },
             "type": "library",
             ],
             "support": {
                 "issues": "https://github.com/myclabs/DeepCopy/issues",
             ],
             "support": {
                 "issues": "https://github.com/myclabs/DeepCopy/issues",
-                "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
+                "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-03-08T13:26:56+00:00"
+            "time": "2025-04-29T12:36:36+00:00"
         },
         {
             "name": "nunomaduro/collision",
         },
         {
             "name": "nunomaduro/collision",
-            "version": "v6.4.0",
+            "version": "v8.8.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nunomaduro/collision.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nunomaduro/collision.git",
-                "reference": "f05978827b9343cba381ca05b8c7deee346b6015"
+                "reference": "44ccb82e3e21efb5446748d2a3c81a030ac22bd5"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nunomaduro/collision/zipball/f05978827b9343cba381ca05b8c7deee346b6015",
-                "reference": "f05978827b9343cba381ca05b8c7deee346b6015",
+                "url": "https://api.github.com/repos/nunomaduro/collision/zipball/44ccb82e3e21efb5446748d2a3c81a030ac22bd5",
+                "reference": "44ccb82e3e21efb5446748d2a3c81a030ac22bd5",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "filp/whoops": "^2.14.5",
-                "php": "^8.0.0",
-                "symfony/console": "^6.0.2"
+                "filp/whoops": "^2.18.1",
+                "nunomaduro/termwind": "^2.3.1",
+                "php": "^8.2.0",
+                "symfony/console": "^7.3.0"
+            },
+            "conflict": {
+                "laravel/framework": "<11.44.2 || >=13.0.0",
+                "phpunit/phpunit": "<11.5.15 || >=13.0.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "brianium/paratest": "^6.4.1",
-                "laravel/framework": "^9.26.1",
-                "laravel/pint": "^1.1.1",
-                "nunomaduro/larastan": "^1.0.3",
-                "nunomaduro/mock-final-classes": "^1.1.0",
-                "orchestra/testbench": "^7.7",
-                "phpunit/phpunit": "^9.5.23",
-                "spatie/ignition": "^1.4.1"
+                "brianium/paratest": "^7.8.3",
+                "larastan/larastan": "^3.4.2",
+                "laravel/framework": "^11.44.2 || ^12.18",
+                "laravel/pint": "^1.22.1",
+                "laravel/sail": "^1.43.1",
+                "laravel/sanctum": "^4.1.1",
+                "laravel/tinker": "^2.10.1",
+                "orchestra/testbench-core": "^9.12.0 || ^10.4",
+                "pestphp/pest": "^3.8.2",
+                "sebastian/environment": "^7.2.1 || ^8.0"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
-                "branch-alias": {
-                    "dev-develop": "6.x-dev"
-                },
                 "laravel": {
                     "providers": [
                         "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider"
                     ]
                 "laravel": {
                     "providers": [
                         "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider"
                     ]
+                },
+                "branch-alias": {
+                    "dev-8.x": "8.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
+                "files": [
+                    "./src/Adapters/Phpunit/Autoload.php"
+                ],
                 "psr-4": {
                     "NunoMaduro\\Collision\\": "src/"
                 }
                 "psr-4": {
                     "NunoMaduro\\Collision\\": "src/"
                 }
                 "cli",
                 "command-line",
                 "console",
                 "cli",
                 "command-line",
                 "console",
+                "dev",
                 "error",
                 "handling",
                 "laravel",
                 "error",
                 "handling",
                 "laravel",
                     "type": "patreon"
                 }
             ],
                     "type": "patreon"
                 }
             ],
-            "time": "2023-01-03T12:54:54+00:00"
+            "time": "2025-06-11T01:04:21+00:00"
         },
         {
             "name": "phar-io/manifest",
         },
         {
             "name": "phar-io/manifest",
         },
         {
             "name": "phpunit/php-code-coverage",
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "9.2.31",
+            "version": "11.0.10",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965"
+                "reference": "1a800a7446add2d79cc6b3c01c45381810367d76"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965",
-                "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76",
+                "reference": "1a800a7446add2d79cc6b3c01c45381810367d76",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
                 "ext-libxml": "*",
                 "ext-xmlwriter": "*",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
                 "ext-libxml": "*",
                 "ext-xmlwriter": "*",
-                "nikic/php-parser": "^4.18 || ^5.0",
-                "php": ">=7.3",
-                "phpunit/php-file-iterator": "^3.0.3",
-                "phpunit/php-text-template": "^2.0.2",
-                "sebastian/code-unit-reverse-lookup": "^2.0.2",
-                "sebastian/complexity": "^2.0",
-                "sebastian/environment": "^5.1.2",
-                "sebastian/lines-of-code": "^1.0.3",
-                "sebastian/version": "^3.0.1",
-                "theseer/tokenizer": "^1.2.0"
+                "nikic/php-parser": "^5.4.0",
+                "php": ">=8.2",
+                "phpunit/php-file-iterator": "^5.1.0",
+                "phpunit/php-text-template": "^4.0.1",
+                "sebastian/code-unit-reverse-lookup": "^4.0.1",
+                "sebastian/complexity": "^4.0.1",
+                "sebastian/environment": "^7.2.0",
+                "sebastian/lines-of-code": "^3.0.1",
+                "sebastian/version": "^5.0.2",
+                "theseer/tokenizer": "^1.2.3"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.5.2"
             },
             "suggest": {
                 "ext-pcov": "PHP extension that provides line coverage",
             },
             "suggest": {
                 "ext-pcov": "PHP extension that provides line coverage",
             "type": "library",
             "extra": {
                 "branch-alias": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.2-dev"
+                    "dev-main": "11.0.x-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
                 "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
                 "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
-                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31"
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show"
             },
             "funding": [
                 {
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
             },
             "funding": [
                 {
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
+                },
+                {
+                    "url": "https://liberapay.com/sebastianbergmann",
+                    "type": "liberapay"
+                },
+                {
+                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
+                    "type": "thanks_dev"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage",
+                    "type": "tidelift"
                 }
             ],
                 }
             ],
-            "time": "2024-03-02T06:37:42+00:00"
+            "time": "2025-06-18T08:56:18+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
         },
         {
             "name": "phpunit/php-file-iterator",
-            "version": "3.0.6",
+            "version": "5.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
-                "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
+                "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
-                "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6",
+                "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-main": "5.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
-                "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
+                "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2021-12-02T12:48:52+00:00"
+            "time": "2024-08-27T05:02:59+00:00"
         },
         {
             "name": "phpunit/php-invoker",
         },
         {
             "name": "phpunit/php-invoker",
-            "version": "3.1.1",
+            "version": "5.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-invoker.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-invoker.git",
-                "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
+                "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
-                "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2",
+                "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
                 "ext-pcntl": "*",
             },
             "require-dev": {
                 "ext-pcntl": "*",
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "suggest": {
                 "ext-pcntl": "*"
             },
             "suggest": {
                 "ext-pcntl": "*"
             "type": "library",
             "extra": {
                 "branch-alias": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1-dev"
+                    "dev-main": "5.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
-                "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
+                "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T05:58:55+00:00"
+            "time": "2024-07-03T05:07:44+00:00"
         },
         {
             "name": "phpunit/php-text-template",
         },
         {
             "name": "phpunit/php-text-template",
-            "version": "2.0.4",
+            "version": "4.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-text-template.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-text-template.git",
-                "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
+                "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
-                "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964",
+                "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-main": "4.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
-                "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
+                "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T05:33:50+00:00"
+            "time": "2024-07-03T05:08:43+00:00"
         },
         {
             "name": "phpunit/php-timer",
         },
         {
             "name": "phpunit/php-timer",
-            "version": "5.0.3",
+            "version": "7.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-timer.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-timer.git",
-                "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
+                "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
-                "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3",
+                "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.0-dev"
+                    "dev-main": "7.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-timer/issues",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-timer/issues",
-                "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
+                "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
+                "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:16:10+00:00"
+            "time": "2024-07-03T05:09:35+00:00"
         },
         {
             "name": "phpunit/phpunit",
         },
         {
             "name": "phpunit/phpunit",
-            "version": "9.6.19",
+            "version": "11.5.24",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8"
+                "reference": "6b07ab1047155cf38f82dd691787a277782271dd"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1a54a473501ef4cdeaae4e06891674114d79db8",
-                "reference": "a1a54a473501ef4cdeaae4e06891674114d79db8",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6b07ab1047155cf38f82dd691787a277782271dd",
+                "reference": "6b07ab1047155cf38f82dd691787a277782271dd",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "doctrine/instantiator": "^1.3.1 || ^2",
                 "ext-dom": "*",
                 "ext-json": "*",
                 "ext-libxml": "*",
                 "ext-mbstring": "*",
                 "ext-xml": "*",
                 "ext-xmlwriter": "*",
                 "ext-dom": "*",
                 "ext-json": "*",
                 "ext-libxml": "*",
                 "ext-mbstring": "*",
                 "ext-xml": "*",
                 "ext-xmlwriter": "*",
-                "myclabs/deep-copy": "^1.10.1",
-                "phar-io/manifest": "^2.0.3",
-                "phar-io/version": "^3.0.2",
-                "php": ">=7.3",
-                "phpunit/php-code-coverage": "^9.2.28",
-                "phpunit/php-file-iterator": "^3.0.5",
-                "phpunit/php-invoker": "^3.1.1",
-                "phpunit/php-text-template": "^2.0.3",
-                "phpunit/php-timer": "^5.0.2",
-                "sebastian/cli-parser": "^1.0.1",
-                "sebastian/code-unit": "^1.0.6",
-                "sebastian/comparator": "^4.0.8",
-                "sebastian/diff": "^4.0.3",
-                "sebastian/environment": "^5.1.3",
-                "sebastian/exporter": "^4.0.5",
-                "sebastian/global-state": "^5.0.1",
-                "sebastian/object-enumerator": "^4.0.3",
-                "sebastian/resource-operations": "^3.0.3",
-                "sebastian/type": "^3.2",
-                "sebastian/version": "^3.0.2"
+                "myclabs/deep-copy": "^1.13.1",
+                "phar-io/manifest": "^2.0.4",
+                "phar-io/version": "^3.2.1",
+                "php": ">=8.2",
+                "phpunit/php-code-coverage": "^11.0.10",
+                "phpunit/php-file-iterator": "^5.1.0",
+                "phpunit/php-invoker": "^5.0.1",
+                "phpunit/php-text-template": "^4.0.1",
+                "phpunit/php-timer": "^7.0.1",
+                "sebastian/cli-parser": "^3.0.2",
+                "sebastian/code-unit": "^3.0.3",
+                "sebastian/comparator": "^6.3.1",
+                "sebastian/diff": "^6.0.2",
+                "sebastian/environment": "^7.2.1",
+                "sebastian/exporter": "^6.3.0",
+                "sebastian/global-state": "^7.0.2",
+                "sebastian/object-enumerator": "^6.0.1",
+                "sebastian/type": "^5.1.2",
+                "sebastian/version": "^5.0.2",
+                "staabm/side-effects-detector": "^1.0.5"
             },
             "suggest": {
             },
             "suggest": {
-                "ext-soap": "To be able to generate mocks based on WSDL files",
-                "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
+                "ext-soap": "To be able to generate mocks based on WSDL files"
             },
             "bin": [
                 "phpunit"
             },
             "bin": [
                 "phpunit"
             "type": "library",
             "extra": {
                 "branch-alias": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.6-dev"
+                    "dev-main": "11.5-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.19"
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.24"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
                 },
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
                 },
+                {
+                    "url": "https://liberapay.com/sebastianbergmann",
+                    "type": "liberapay"
+                },
+                {
+                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
+                    "type": "thanks_dev"
+                },
                 {
                     "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
                     "type": "tidelift"
                 }
             ],
                 {
                     "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-04-05T04:35:58+00:00"
+            "time": "2025-06-20T11:31:02+00:00"
         },
         {
             "name": "sebastian/cli-parser",
         },
         {
             "name": "sebastian/cli-parser",
-            "version": "1.0.2",
+            "version": "3.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/cli-parser.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/cli-parser.git",
-                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
+                "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
-                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
+                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180",
+                "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-main": "3.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/sebastianbergmann/cli-parser",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
             "homepage": "https://github.com/sebastianbergmann/cli-parser",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
-                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
+                "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+                "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:27:43+00:00"
+            "time": "2024-07-03T04:41:36+00:00"
         },
         {
             "name": "sebastian/code-unit",
         },
         {
             "name": "sebastian/code-unit",
-            "version": "1.0.8",
+            "version": "3.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/code-unit.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/code-unit.git",
-                "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
+                "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
-                "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64",
+                "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.5"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-main": "3.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/sebastianbergmann/code-unit",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/code-unit/issues",
             "homepage": "https://github.com/sebastianbergmann/code-unit",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/code-unit/issues",
-                "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
+                "security": "https://github.com/sebastianbergmann/code-unit/security/policy",
+                "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:08:54+00:00"
+            "time": "2025-03-19T07:56:08+00:00"
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",
-            "version": "2.0.3",
+            "version": "4.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
-                "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
+                "reference": "183a9b2632194febd219bb9246eee421dad8d45e"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
-                "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+                "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e",
+                "reference": "183a9b2632194febd219bb9246eee421dad8d45e",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-main": "4.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
             "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
-                "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
+                "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy",
+                "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T05:30:19+00:00"
+            "time": "2024-07-03T04:45:54+00:00"
         },
         {
             "name": "sebastian/comparator",
         },
         {
             "name": "sebastian/comparator",
-            "version": "4.0.8",
+            "version": "6.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/comparator.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/comparator.git",
-                "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
+                "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
-                "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959",
+                "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
-                "sebastian/diff": "^4.0",
-                "sebastian/exporter": "^4.0"
+                "ext-dom": "*",
+                "ext-mbstring": "*",
+                "php": ">=8.2",
+                "sebastian/diff": "^6.0",
+                "sebastian/exporter": "^6.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.4"
+            },
+            "suggest": {
+                "ext-bcmath": "For comparing BcMath\\Number objects"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "6.3-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/comparator/issues",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/comparator/issues",
-                "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
+                "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+                "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2022-09-14T12:41:17+00:00"
+            "time": "2025-03-07T06:57:01+00:00"
         },
         {
             "name": "sebastian/complexity",
         },
         {
             "name": "sebastian/complexity",
-            "version": "2.0.3",
+            "version": "4.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/complexity.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/complexity.git",
-                "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
+                "reference": "ee41d384ab1906c68852636b6de493846e13e5a0"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
-                "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
+                "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0",
+                "reference": "ee41d384ab1906c68852636b6de493846e13e5a0",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "nikic/php-parser": "^4.18 || ^5.0",
-                "php": ">=7.3"
+                "nikic/php-parser": "^5.0",
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-main": "4.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/sebastianbergmann/complexity",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/complexity/issues",
             "homepage": "https://github.com/sebastianbergmann/complexity",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/complexity/issues",
-                "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
+                "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+                "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-12-22T06:19:30+00:00"
+            "time": "2024-07-03T04:49:50+00:00"
         },
         {
             "name": "sebastian/diff",
         },
         {
             "name": "sebastian/diff",
-            "version": "4.0.6",
+            "version": "6.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/diff.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
+                "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
-                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544",
+                "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3",
+                "phpunit/phpunit": "^11.0",
                 "symfony/process": "^4.2 || ^5"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
                 "symfony/process": "^4.2 || ^5"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "6.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/diff/issues",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/diff/issues",
-                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
+                "security": "https://github.com/sebastianbergmann/diff/security/policy",
+                "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:30:58+00:00"
+            "time": "2024-07-03T04:53:05+00:00"
         },
         {
             "name": "sebastian/environment",
         },
         {
             "name": "sebastian/environment",
-            "version": "5.1.5",
+            "version": "7.2.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/environment.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/environment.git",
-                "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
+                "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
-                "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
+                "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4",
+                "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.3"
             },
             "suggest": {
                 "ext-posix": "*"
             },
             "suggest": {
                 "ext-posix": "*"
             "type": "library",
             "extra": {
                 "branch-alias": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.1-dev"
+                    "dev-main": "7.2-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 }
             ],
             "description": "Provides functionality to handle HHVM/PHP environments",
                 }
             ],
             "description": "Provides functionality to handle HHVM/PHP environments",
-            "homepage": "http://www.github.com/sebastianbergmann/environment",
+            "homepage": "https://github.com/sebastianbergmann/environment",
             "keywords": [
                 "Xdebug",
                 "environment",
             "keywords": [
                 "Xdebug",
                 "environment",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/environment/issues",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/environment/issues",
-                "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
+                "security": "https://github.com/sebastianbergmann/environment/security/policy",
+                "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1"
             },
             "funding": [
                 {
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
             },
             "funding": [
                 {
                     "url": "https://github.com/sebastianbergmann",
                     "type": "github"
+                },
+                {
+                    "url": "https://liberapay.com/sebastianbergmann",
+                    "type": "liberapay"
+                },
+                {
+                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
+                    "type": "thanks_dev"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/sebastian/environment",
+                    "type": "tidelift"
                 }
             ],
                 }
             ],
-            "time": "2023-02-03T06:03:51+00:00"
+            "time": "2025-05-21T11:55:47+00:00"
         },
         {
             "name": "sebastian/exporter",
         },
         {
             "name": "sebastian/exporter",
-            "version": "4.0.6",
+            "version": "6.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
+                "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
-                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3",
+                "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
-                "sebastian/recursion-context": "^4.0"
+                "ext-mbstring": "*",
+                "php": ">=8.2",
+                "sebastian/recursion-context": "^6.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "ext-mbstring": "*",
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.3"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "6.1-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/exporter/issues",
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/exporter/issues",
-                "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
+                "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+                "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:33:00+00:00"
+            "time": "2024-12-05T09:17:50+00:00"
         },
         {
             "name": "sebastian/global-state",
         },
         {
             "name": "sebastian/global-state",
-            "version": "5.0.7",
+            "version": "7.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
+                "reference": "3be331570a721f9a4b5917f4209773de17f747d7"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
-                "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7",
+                "reference": "3be331570a721f9a4b5917f4209773de17f747d7",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
-                "sebastian/object-reflector": "^2.0",
-                "sebastian/recursion-context": "^4.0"
+                "php": ">=8.2",
+                "sebastian/object-reflector": "^4.0",
+                "sebastian/recursion-context": "^6.0"
             },
             "require-dev": {
                 "ext-dom": "*",
             },
             "require-dev": {
                 "ext-dom": "*",
-                "phpunit/phpunit": "^9.3"
-            },
-            "suggest": {
-                "ext-uopz": "*"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "5.0-dev"
+                    "dev-main": "7.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                 }
             ],
             "description": "Snapshotting of global state",
                 }
             ],
             "description": "Snapshotting of global state",
-            "homepage": "http://www.github.com/sebastianbergmann/global-state",
+            "homepage": "https://www.github.com/sebastianbergmann/global-state",
             "keywords": [
                 "global state"
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/global-state/issues",
             "keywords": [
                 "global state"
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/global-state/issues",
-                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
+                "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+                "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-03-02T06:35:11+00:00"
+            "time": "2024-07-03T04:57:36+00:00"
         },
         {
             "name": "sebastian/lines-of-code",
         },
         {
             "name": "sebastian/lines-of-code",
-            "version": "1.0.4",
+            "version": "3.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/lines-of-code.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/lines-of-code.git",
-                "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
+                "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
-                "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
+                "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a",
+                "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "nikic/php-parser": "^4.18 || ^5.0",
-                "php": ">=7.3"
+                "nikic/php-parser": "^5.0",
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0-dev"
+                    "dev-main": "3.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/sebastianbergmann/lines-of-code",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
             "homepage": "https://github.com/sebastianbergmann/lines-of-code",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
-                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
+                "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+                "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-12-22T06:20:34+00:00"
+            "time": "2024-07-03T04:58:38+00:00"
         },
         {
             "name": "sebastian/object-enumerator",
         },
         {
             "name": "sebastian/object-enumerator",
-            "version": "4.0.4",
+            "version": "6.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/object-enumerator.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/object-enumerator.git",
-                "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
+                "reference": "f5b498e631a74204185071eb41f33f38d64608aa"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
-                "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa",
+                "reference": "f5b498e631a74204185071eb41f33f38d64608aa",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3",
-                "sebastian/object-reflector": "^2.0",
-                "sebastian/recursion-context": "^4.0"
+                "php": ">=8.2",
+                "sebastian/object-reflector": "^4.0",
+                "sebastian/recursion-context": "^6.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "6.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
             "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
-                "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
+                "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
+                "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:12:34+00:00"
+            "time": "2024-07-03T05:00:13+00:00"
         },
         {
             "name": "sebastian/object-reflector",
         },
         {
             "name": "sebastian/object-reflector",
-            "version": "2.0.4",
+            "version": "4.0.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/object-reflector.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/object-reflector.git",
-                "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
+                "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
-                "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+                "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9",
+                "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0-dev"
+                    "dev-main": "4.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/sebastianbergmann/object-reflector/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
             "homepage": "https://github.com/sebastianbergmann/object-reflector/",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
-                "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
+                "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
+                "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2020-10-26T13:14:26+00:00"
+            "time": "2024-07-03T05:01:32+00:00"
         },
         {
             "name": "sebastian/recursion-context",
         },
         {
             "name": "sebastian/recursion-context",
-            "version": "4.0.5",
+            "version": "6.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/recursion-context.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/recursion-context.git",
-                "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
+                "reference": "694d156164372abbd149a4b85ccda2e4670c0e16"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
-                "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
+                "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16",
+                "reference": "694d156164372abbd149a4b85ccda2e4670c0e16",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^11.0"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.0-dev"
+                    "dev-main": "6.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "homepage": "https://github.com/sebastianbergmann/recursion-context",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
             "homepage": "https://github.com/sebastianbergmann/recursion-context",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
-                "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
+                "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+                "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-02-03T06:07:39+00:00"
+            "time": "2024-07-03T05:10:34+00:00"
         },
         {
         },
         {
-            "name": "sebastian/resource-operations",
-            "version": "3.0.4",
+            "name": "sebastian/type",
+            "version": "5.1.2",
             "source": {
                 "type": "git",
             "source": {
                 "type": "git",
-                "url": "https://github.com/sebastianbergmann/resource-operations.git",
-                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
+                "url": "https://github.com/sebastianbergmann/type.git",
+                "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
-                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
+                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e",
+                "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": ">=8.2"
             },
             "require-dev": {
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.0"
+                "phpunit/phpunit": "^11.3"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-main": "3.0-dev"
+                    "dev-main": "5.1-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
             "authors": [
                 {
                     "name": "Sebastian Bergmann",
             "authors": [
                 {
                     "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de"
+                    "email": "sebastian@phpunit.de",
+                    "role": "lead"
                 }
             ],
                 }
             ],
-            "description": "Provides a list of PHP built-in functions that operate on resources",
-            "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+            "description": "Collection of value objects that represent the types of the PHP type system",
+            "homepage": "https://github.com/sebastianbergmann/type",
             "support": {
             "support": {
-                "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
+                "issues": "https://github.com/sebastianbergmann/type/issues",
+                "security": "https://github.com/sebastianbergmann/type/security/policy",
+                "source": "https://github.com/sebastianbergmann/type/tree/5.1.2"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-03-14T16:00:52+00:00"
+            "time": "2025-03-18T13:35:50+00:00"
         },
         {
         },
         {
-            "name": "sebastian/type",
-            "version": "3.2.1",
+            "name": "sebastian/version",
+            "version": "5.0.2",
             "source": {
                 "type": "git",
             "source": {
                 "type": "git",
-                "url": "https://github.com/sebastianbergmann/type.git",
-                "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
+                "url": "https://github.com/sebastianbergmann/version.git",
+                "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
-                "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
+                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874",
+                "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
-            },
-            "require-dev": {
-                "phpunit/phpunit": "^9.5"
+                "php": ">=8.2"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.2-dev"
+                    "dev-main": "5.0-dev"
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                     "role": "lead"
                 }
             ],
                     "role": "lead"
                 }
             ],
-            "description": "Collection of value objects that represent the types of the PHP type system",
-            "homepage": "https://github.com/sebastianbergmann/type",
+            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+            "homepage": "https://github.com/sebastianbergmann/version",
             "support": {
             "support": {
-                "issues": "https://github.com/sebastianbergmann/type/issues",
-                "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
+                "issues": "https://github.com/sebastianbergmann/version/issues",
+                "security": "https://github.com/sebastianbergmann/version/security/policy",
+                "source": "https://github.com/sebastianbergmann/version/tree/5.0.2"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2023-02-03T06:13:03+00:00"
+            "time": "2024-10-09T05:16:32+00:00"
         },
         {
         },
         {
-            "name": "sebastian/version",
-            "version": "3.0.2",
+            "name": "spatie/backtrace",
+            "version": "1.7.4",
             "source": {
                 "type": "git",
             "source": {
                 "type": "git",
-                "url": "https://github.com/sebastianbergmann/version.git",
-                "reference": "c6c1022351a901512170118436c764e473f6de8c"
+                "url": "https://github.com/spatie/backtrace.git",
+                "reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
-                "reference": "c6c1022351a901512170118436c764e473f6de8c",
+                "url": "https://api.github.com/repos/spatie/backtrace/zipball/cd37a49fce7137359ac30ecc44ef3e16404cccbe",
+                "reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": ">=7.3"
+                "php": "^7.3 || ^8.0"
             },
             },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.0-dev"
-                }
+            "require-dev": {
+                "ext-json": "*",
+                "laravel/serializable-closure": "^1.3 || ^2.0",
+                "phpunit/phpunit": "^9.3 || ^11.4.3",
+                "spatie/phpunit-snapshot-assertions": "^4.2 || ^5.1.6",
+                "symfony/var-dumper": "^5.1 || ^6.0 || ^7.0"
             },
             },
+            "type": "library",
             "autoload": {
             "autoload": {
-                "classmap": [
-                    "src/"
-                ]
+                "psr-4": {
+                    "Spatie\\Backtrace\\": "src"
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "BSD-3-Clause"
+                "MIT"
             ],
             "authors": [
                 {
             ],
             "authors": [
                 {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
+                    "name": "Freek Van de Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
                 }
             ],
                 }
             ],
-            "description": "Library that helps with managing the version number of Git-hosted PHP projects",
-            "homepage": "https://github.com/sebastianbergmann/version",
+            "description": "A better backtrace",
+            "homepage": "https://github.com/spatie/backtrace",
+            "keywords": [
+                "Backtrace",
+                "spatie"
+            ],
             "support": {
             "support": {
-                "issues": "https://github.com/sebastianbergmann/version/issues",
-                "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
+                "source": "https://github.com/spatie/backtrace/tree/1.7.4"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
-                    "url": "https://github.com/sebastianbergmann",
+                    "url": "https://github.com/sponsors/spatie",
                     "type": "github"
                     "type": "github"
+                },
+                {
+                    "url": "https://spatie.be/open-source/support-us",
+                    "type": "other"
                 }
             ],
                 }
             ],
-            "time": "2020-09-28T06:39:44+00:00"
+            "time": "2025-05-08T15:41:09+00:00"
         },
         {
         },
         {
-            "name": "spatie/backtrace",
-            "version": "1.5.3",
+            "name": "spatie/error-solutions",
+            "version": "1.1.3",
             "source": {
                 "type": "git",
             "source": {
                 "type": "git",
-                "url": "https://github.com/spatie/backtrace.git",
-                "reference": "483f76a82964a0431aa836b6ed0edde0c248e3ab"
+                "url": "https://github.com/spatie/error-solutions.git",
+                "reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/spatie/backtrace/zipball/483f76a82964a0431aa836b6ed0edde0c248e3ab",
-                "reference": "483f76a82964a0431aa836b6ed0edde0c248e3ab",
+                "url": "https://api.github.com/repos/spatie/error-solutions/zipball/e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
+                "reference": "e495d7178ca524f2dd0fe6a1d99a1e608e1c9936",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "php": "^7.3|^8.0"
+                "php": "^8.0"
             },
             "require-dev": {
             },
             "require-dev": {
-                "ext-json": "*",
-                "phpunit/phpunit": "^9.3",
-                "spatie/phpunit-snapshot-assertions": "^4.2",
-                "symfony/var-dumper": "^5.1"
+                "illuminate/broadcasting": "^10.0|^11.0|^12.0",
+                "illuminate/cache": "^10.0|^11.0|^12.0",
+                "illuminate/support": "^10.0|^11.0|^12.0",
+                "livewire/livewire": "^2.11|^3.5.20",
+                "openai-php/client": "^0.10.1",
+                "orchestra/testbench": "8.22.3|^9.0|^10.0",
+                "pestphp/pest": "^2.20|^3.0",
+                "phpstan/phpstan": "^2.1",
+                "psr/simple-cache": "^3.0",
+                "psr/simple-cache-implementation": "^3.0",
+                "spatie/ray": "^1.28",
+                "symfony/cache": "^5.4|^6.0|^7.0",
+                "symfony/process": "^5.4|^6.0|^7.0",
+                "vlucas/phpdotenv": "^5.5"
+            },
+            "suggest": {
+                "openai-php/client": "Require get solutions from OpenAI",
+                "simple-cache-implementation": "To cache solutions from OpenAI"
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
             },
             "type": "library",
             "autoload": {
                 "psr-4": {
-                    "Spatie\\Backtrace\\": "src"
+                    "Spatie\\Ignition\\": "legacy/ignition",
+                    "Spatie\\ErrorSolutions\\": "src",
+                    "Spatie\\LaravelIgnition\\": "legacy/laravel-ignition"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
             ],
             "authors": [
                 {
             ],
             "authors": [
                 {
-                    "name": "Freek Van de Herten",
-                    "email": "freek@spatie.be",
-                    "homepage": "https://spatie.be",
+                    "name": "Ruben Van Assche",
+                    "email": "ruben@spatie.be",
                     "role": "Developer"
                 }
             ],
                     "role": "Developer"
                 }
             ],
-            "description": "A better backtrace",
-            "homepage": "https://github.com/spatie/backtrace",
+            "description": "This is my package error-solutions",
+            "homepage": "https://github.com/spatie/error-solutions",
             "keywords": [
             "keywords": [
-                "Backtrace",
+                "error-solutions",
                 "spatie"
             ],
             "support": {
                 "spatie"
             ],
             "support": {
-                "source": "https://github.com/spatie/backtrace/tree/1.5.3"
+                "issues": "https://github.com/spatie/error-solutions/issues",
+                "source": "https://github.com/spatie/error-solutions/tree/1.1.3"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
-                    "url": "https://github.com/sponsors/spatie",
+                    "url": "https://github.com/Spatie",
                     "type": "github"
                     "type": "github"
-                },
-                {
-                    "url": "https://spatie.be/open-source/support-us",
-                    "type": "other"
                 }
             ],
                 }
             ],
-            "time": "2023-06-28T12:59:17+00:00"
+            "time": "2025-02-14T12:29:50+00:00"
         },
         {
             "name": "spatie/flare-client-php",
         },
         {
             "name": "spatie/flare-client-php",
-            "version": "1.4.4",
+            "version": "1.10.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/flare-client-php.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/flare-client-php.git",
-                "reference": "17082e780752d346c2db12ef5d6bee8e835e399c"
+                "reference": "bf1716eb98bd689451b071548ae9e70738dce62f"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/spatie/flare-client-php/zipball/17082e780752d346c2db12ef5d6bee8e835e399c",
-                "reference": "17082e780752d346c2db12ef5d6bee8e835e399c",
+                "url": "https://api.github.com/repos/spatie/flare-client-php/zipball/bf1716eb98bd689451b071548ae9e70738dce62f",
+                "reference": "bf1716eb98bd689451b071548ae9e70738dce62f",
                 "shasum": ""
             },
             "require": {
                 "shasum": ""
             },
             "require": {
-                "illuminate/pipeline": "^8.0|^9.0|^10.0|^11.0",
+                "illuminate/pipeline": "^8.0|^9.0|^10.0|^11.0|^12.0",
                 "php": "^8.0",
                 "php": "^8.0",
-                "spatie/backtrace": "^1.5.2",
+                "spatie/backtrace": "^1.6.1",
                 "symfony/http-foundation": "^5.2|^6.0|^7.0",
                 "symfony/mime": "^5.2|^6.0|^7.0",
                 "symfony/process": "^5.2|^6.0|^7.0",
                 "symfony/http-foundation": "^5.2|^6.0|^7.0",
                 "symfony/mime": "^5.2|^6.0|^7.0",
                 "symfony/process": "^5.2|^6.0|^7.0",
                 "phpstan/extension-installer": "^1.1",
                 "phpstan/phpstan-deprecation-rules": "^1.0",
                 "phpstan/phpstan-phpunit": "^1.0",
                 "phpstan/extension-installer": "^1.1",
                 "phpstan/phpstan-deprecation-rules": "^1.0",
                 "phpstan/phpstan-phpunit": "^1.0",
-                "spatie/phpunit-snapshot-assertions": "^4.0|^5.0"
+                "spatie/pest-plugin-snapshots": "^1.0|^2.0"
             },
             "type": "library",
             "extra": {
             },
             "type": "library",
             "extra": {
             ],
             "support": {
                 "issues": "https://github.com/spatie/flare-client-php/issues",
             ],
             "support": {
                 "issues": "https://github.com/spatie/flare-client-php/issues",
-                "source": "https://github.com/spatie/flare-client-php/tree/1.4.4"
+                "source": "https://github.com/spatie/flare-client-php/tree/1.10.1"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-01-31T14:18:45+00:00"
+            "time": "2025-02-14T13:42:06+00:00"
         },
         {
             "name": "spatie/ignition",
         },
         {
             "name": "spatie/ignition",
-            "version": "1.13.1",
+            "version": "1.15.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/ignition.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/ignition.git",
-                "reference": "889bf1dfa59e161590f677728b47bf4a6893983b"
+                "reference": "31f314153020aee5af3537e507fef892ffbf8c85"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/spatie/ignition/zipball/889bf1dfa59e161590f677728b47bf4a6893983b",
-                "reference": "889bf1dfa59e161590f677728b47bf4a6893983b",
+                "url": "https://api.github.com/repos/spatie/ignition/zipball/31f314153020aee5af3537e507fef892ffbf8c85",
+                "reference": "31f314153020aee5af3537e507fef892ffbf8c85",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
                 "ext-mbstring": "*",
                 "php": "^8.0",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
                 "ext-mbstring": "*",
                 "php": "^8.0",
-                "spatie/backtrace": "^1.5.3",
-                "spatie/flare-client-php": "^1.4.0",
+                "spatie/error-solutions": "^1.0",
+                "spatie/flare-client-php": "^1.7",
                 "symfony/console": "^5.4|^6.0|^7.0",
                 "symfony/var-dumper": "^5.4|^6.0|^7.0"
             },
             "require-dev": {
                 "symfony/console": "^5.4|^6.0|^7.0",
                 "symfony/var-dumper": "^5.4|^6.0|^7.0"
             },
             "require-dev": {
-                "illuminate/cache": "^9.52|^10.0|^11.0",
+                "illuminate/cache": "^9.52|^10.0|^11.0|^12.0",
                 "mockery/mockery": "^1.4",
                 "pestphp/pest": "^1.20|^2.0",
                 "phpstan/extension-installer": "^1.1",
                 "mockery/mockery": "^1.4",
                 "pestphp/pest": "^1.20|^2.0",
                 "phpstan/extension-installer": "^1.1",
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-03-29T14:03:47+00:00"
+            "time": "2025-02-21T14:31:39+00:00"
         },
         {
             "name": "spatie/laravel-ignition",
         },
         {
             "name": "spatie/laravel-ignition",
-            "version": "2.5.1",
+            "version": "2.9.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/laravel-ignition.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/laravel-ignition.git",
-                "reference": "0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9"
+                "reference": "1baee07216d6748ebd3a65ba97381b051838707a"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9",
-                "reference": "0c864b3cbd66ce67a2096c5f743e07ce8f1d6ab9",
+                "url": "https://api.github.com/repos/spatie/laravel-ignition/zipball/1baee07216d6748ebd3a65ba97381b051838707a",
+                "reference": "1baee07216d6748ebd3a65ba97381b051838707a",
                 "shasum": ""
             },
             "require": {
                 "ext-curl": "*",
                 "ext-json": "*",
                 "ext-mbstring": "*",
                 "shasum": ""
             },
             "require": {
                 "ext-curl": "*",
                 "ext-json": "*",
                 "ext-mbstring": "*",
-                "illuminate/support": "^10.0|^11.0",
+                "illuminate/support": "^10.0|^11.0|^12.0",
                 "php": "^8.1",
                 "php": "^8.1",
-                "spatie/flare-client-php": "^1.3.5",
-                "spatie/ignition": "^1.13",
+                "spatie/ignition": "^1.15",
                 "symfony/console": "^6.2.3|^7.0",
                 "symfony/var-dumper": "^6.2.3|^7.0"
             },
             "require-dev": {
                 "livewire/livewire": "^2.11|^3.3.5",
                 "mockery/mockery": "^1.5.1",
                 "symfony/console": "^6.2.3|^7.0",
                 "symfony/var-dumper": "^6.2.3|^7.0"
             },
             "require-dev": {
                 "livewire/livewire": "^2.11|^3.3.5",
                 "mockery/mockery": "^1.5.1",
-                "openai-php/client": "^0.8.1",
-                "orchestra/testbench": "^8.0|^9.0",
-                "pestphp/pest": "^2.30",
-                "phpstan/extension-installer": "^1.2",
-                "phpstan/phpstan-deprecation-rules": "^1.1.1",
-                "phpstan/phpstan-phpunit": "^1.3.3",
+                "openai-php/client": "^0.8.1|^0.10",
+                "orchestra/testbench": "8.22.3|^9.0|^10.0",
+                "pestphp/pest": "^2.34|^3.7",
+                "phpstan/extension-installer": "^1.3.1",
+                "phpstan/phpstan-deprecation-rules": "^1.1.1|^2.0",
+                "phpstan/phpstan-phpunit": "^1.3.16|^2.0",
                 "vlucas/phpdotenv": "^5.5"
             },
             "suggest": {
                 "vlucas/phpdotenv": "^5.5"
             },
             "suggest": {
             "type": "library",
             "extra": {
                 "laravel": {
             "type": "library",
             "extra": {
                 "laravel": {
-                    "providers": [
-                        "Spatie\\LaravelIgnition\\IgnitionServiceProvider"
-                    ],
                     "aliases": {
                         "Flare": "Spatie\\LaravelIgnition\\Facades\\Flare"
                     "aliases": {
                         "Flare": "Spatie\\LaravelIgnition\\Facades\\Flare"
-                    }
+                    },
+                    "providers": [
+                        "Spatie\\LaravelIgnition\\IgnitionServiceProvider"
+                    ]
                 }
             },
             "autoload": {
                 }
             },
             "autoload": {
                     "type": "github"
                 }
             ],
                     "type": "github"
                 }
             ],
-            "time": "2024-04-02T06:30:22+00:00"
+            "time": "2025-02-20T13:13:55+00:00"
+        },
+        {
+            "name": "staabm/side-effects-detector",
+            "version": "1.0.5",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/staabm/side-effects-detector.git",
+                "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
+                "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
+                "shasum": ""
+            },
+            "require": {
+                "ext-tokenizer": "*",
+                "php": "^7.4 || ^8.0"
+            },
+            "require-dev": {
+                "phpstan/extension-installer": "^1.4.3",
+                "phpstan/phpstan": "^1.12.6",
+                "phpunit/phpunit": "^9.6.21",
+                "symfony/var-dumper": "^5.4.43",
+                "tomasvotruba/type-coverage": "1.0.0",
+                "tomasvotruba/unused-public": "1.0.0"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "lib/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "A static analysis tool to detect side effects in PHP code",
+            "keywords": [
+                "static analysis"
+            ],
+            "support": {
+                "issues": "https://github.com/staabm/side-effects-detector/issues",
+                "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/staabm",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-10-20T05:08:20+00:00"
         },
         {
             "name": "symfony/yaml",
         },
         {
             "name": "symfony/yaml",
-            "version": "v7.0.3",
+            "version": "v7.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/yaml.git",
-                "reference": "2d4fca631c00700597e9442a0b2451ce234513d3"
+                "reference": "cea40a48279d58dc3efee8112634cb90141156c2"
             },
             "dist": {
                 "type": "zip",
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/2d4fca631c00700597e9442a0b2451ce234513d3",
-                "reference": "2d4fca631c00700597e9442a0b2451ce234513d3",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/cea40a48279d58dc3efee8112634cb90141156c2",
+                "reference": "cea40a48279d58dc3efee8112634cb90141156c2",
                 "shasum": ""
             },
             "require": {
                 "php": ">=8.2",
                 "shasum": ""
             },
             "require": {
                 "php": ">=8.2",
+                "symfony/deprecation-contracts": "^2.5|^3.0",
                 "symfony/polyfill-ctype": "^1.8"
             },
             "conflict": {
                 "symfony/polyfill-ctype": "^1.8"
             },
             "conflict": {
             "description": "Loads and dumps YAML files",
             "homepage": "https://symfony.com",
             "support": {
             "description": "Loads and dumps YAML files",
             "homepage": "https://symfony.com",
             "support": {
-                "source": "https://github.com/symfony/yaml/tree/v7.0.3"
+                "source": "https://github.com/symfony/yaml/tree/v7.3.0"
             },
             "funding": [
                 {
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
                     "type": "tidelift"
                 }
             ],
-            "time": "2024-01-23T15:02:46+00:00"
+            "time": "2025-04-04T10:10:33+00:00"
         },
         {
             "name": "theseer/tokenizer",
         },
         {
             "name": "theseer/tokenizer",
     ],
     "aliases": [],
     "minimum-stability": "dev",
     ],
     "aliases": [],
     "minimum-stability": "dev",
-    "stability-flags": [],
+    "stability-flags": {},
     "prefer-stable": true,
     "prefer-lowest": false,
     "platform": {
     "prefer-stable": true,
     "prefer-lowest": false,
     "platform": {
-        "php": "^8.1"
+        "php": "^8.2"
     },
     },
-    "platform-dev": [],
-    "plugin-api-version": "2.3.0"
+    "platform-dev": {},
+    "plugin-api-version": "2.6.0"
 }
 }
index fcedd9fa807b9b519a5f17a863cc283e32f7ce4a..7d0646cf5ceed01d28b735df17fa9b904a558af1 100644 (file)
@@ -30,6 +30,22 @@ return [
 
     'connections' => [
 
 
     'connections' => [
 
+        'reverb' => [
+            'driver' => 'reverb',
+            'key' => env('REVERB_APP_KEY'),
+            'secret' => env('REVERB_APP_SECRET'),
+            'app_id' => env('REVERB_APP_ID'),
+            'options' => [
+                'host' => env('REVERB_HOST'),
+                'port' => env('REVERB_PORT', 443),
+                'scheme' => env('REVERB_SCHEME', 'https'),
+                'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
+            ],
+            'client_options' => [
+                // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html
+            ],
+        ],
+
         'pusher' => [
             'driver' => 'pusher',
             'key' => env('PUSHER_APP_KEY'),
         'pusher' => [
             'driver' => 'pusher',
             'key' => env('PUSHER_APP_KEY'),
index ee52e708bd0bad3d00bd8308e46297ee61ab0c43..35068d5d84337db5de2267e513892614ec559c1b 100644 (file)
@@ -101,4 +101,10 @@ return [
         'database_error' => 'There was an error with the database. Please try again later.',
     ],
 
         'database_error' => 'There was an error with the database. Please try again later.',
     ],
 
+       'guilds' => [],
+
+       'guild_roles' => [],
+
+       'remember_me' => true,
+
 ];
 ];
diff --git a/config/reverb.php b/config/reverb.php
new file mode 100644 (file)
index 0000000..798ead6
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+
+return [
+
+    /*
+    |--------------------------------------------------------------------------
+    | Default Reverb Server
+    |--------------------------------------------------------------------------
+    |
+    | This option controls the default server used by Reverb to handle
+    | incoming messages as well as broadcasting message to all your
+    | connected clients. At this time only "reverb" is supported.
+    |
+    */
+
+    'default' => env('REVERB_SERVER', 'reverb'),
+
+    /*
+    |--------------------------------------------------------------------------
+    | Reverb Servers
+    |--------------------------------------------------------------------------
+    |
+    | Here you may define details for each of the supported Reverb servers.
+    | Each server has its own configuration options that are defined in
+    | the array below. You should ensure all the options are present.
+    |
+    */
+
+    'servers' => [
+
+        'reverb' => [
+            'host' => env('REVERB_SERVER_HOST', '0.0.0.0'),
+            'port' => env('REVERB_SERVER_PORT', 8080),
+            'hostname' => env('REVERB_HOST'),
+            'options' => [
+                'tls' => [],
+            ],
+            'max_request_size' => env('REVERB_MAX_REQUEST_SIZE', 10_000),
+            'scaling' => [
+                'enabled' => env('REVERB_SCALING_ENABLED', false),
+                'channel' => env('REVERB_SCALING_CHANNEL', 'reverb'),
+                'server' => [
+                    'url' => env('REDIS_URL'),
+                    'host' => env('REDIS_HOST', '127.0.0.1'),
+                    'port' => env('REDIS_PORT', '6379'),
+                    'username' => env('REDIS_USERNAME'),
+                    'password' => env('REDIS_PASSWORD'),
+                    'database' => env('REDIS_DB', '0'),
+                ],
+            ],
+            'pulse_ingest_interval' => env('REVERB_PULSE_INGEST_INTERVAL', 15),
+            'telescope_ingest_interval' => env('REVERB_TELESCOPE_INGEST_INTERVAL', 15),
+        ],
+
+    ],
+
+    /*
+    |--------------------------------------------------------------------------
+    | Reverb Applications
+    |--------------------------------------------------------------------------
+    |
+    | Here you may define how Reverb applications are managed. If you choose
+    | to use the "config" provider, you may define an array of apps which
+    | your server will support, including their connection credentials.
+    |
+    */
+
+    'apps' => [
+
+        'provider' => 'config',
+
+        'apps' => [
+            [
+                'key' => env('REVERB_APP_KEY'),
+                'secret' => env('REVERB_APP_SECRET'),
+                'app_id' => env('REVERB_APP_ID'),
+                'options' => [
+                    'host' => env('REVERB_HOST'),
+                    'port' => env('REVERB_PORT', 443),
+                    'scheme' => env('REVERB_SCHEME', 'https'),
+                    'useTLS' => env('REVERB_SCHEME', 'https') === 'https',
+                ],
+                'allowed_origins' => ['*'],
+                'ping_interval' => env('REVERB_APP_PING_INTERVAL', 60),
+                'max_message_size' => env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000),
+            ],
+        ],
+
+    ],
+
+];
diff --git a/database/migrations/2023_05_25_121158_add_remember_token_to_users_table.php b/database/migrations/2023_05_25_121158_add_remember_token_to_users_table.php
new file mode 100644 (file)
index 0000000..13f0499
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->rememberToken()->after('refresh_token');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->dropRememberToken();
+        });
+    }
+};
diff --git a/database/migrations/2023_05_26_165816_create_discord_access_tokens_table.php b/database/migrations/2023_05_26_165816_create_discord_access_tokens_table.php
new file mode 100644 (file)
index 0000000..2f8afec
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::create('discord_access_tokens', function (Blueprint $table) {
+            $table->id();
+            $table->string('access_token');
+            $table->string('refresh_token');
+            $table->string('token_type');
+            $table->integer('expires_in');
+            $table->timestamp('expires_at');
+            $table->string('scope');
+            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
+            $table->timestamps();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::dropIfExists('discord_access_tokens');
+    }
+};
diff --git a/database/migrations/2023_05_27_055058_remove_refresh_token_from_users_table.php b/database/migrations/2023_05_27_055058_remove_refresh_token_from_users_table.php
new file mode 100644 (file)
index 0000000..a6c14da
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->dropColumn('refresh_token');
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->string('refresh_token')->nullable();
+        });
+    }
+};
diff --git a/database/migrations/2023_06_11_062809_update_users_table.php b/database/migrations/2023_06_11_062809_update_users_table.php
new file mode 100644 (file)
index 0000000..9b903d9
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->string('global_name')->nullable()->after('username');
+            $table->string('discriminator')->nullable()->change();
+            $table->string('banner')->nullable()->after('verified');
+            $table->string('banner_color')->nullable()->after('banner');
+            $table->string('accent_color')->nullable()->after('banner_color');
+            $table->string('premium_type')->nullable()->after('mfa_enabled');
+            $table->string('public_flags')->nullable()->after('premium_type');
+            $table->boolean('verified')->nullable()->change();
+        });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        Schema::table('users', function (Blueprint $table) {
+            $table->dropColumn('global_name');
+            $table->string('discriminator')->change();
+            $table->dropColumn('banner');
+            $table->dropColumn('banner_color');
+            $table->dropColumn('accent_color');
+            $table->dropColumn('premium_type');
+            $table->dropColumn('public_flags');
+            $table->boolean('verified')->change();
+        });
+    }
+};
diff --git a/database/migrations/2024_07_13_124353_chat_logs_emote_only.php b/database/migrations/2024_07_13_124353_chat_logs_emote_only.php
new file mode 100644 (file)
index 0000000..0f3b7f9
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+       /**
+        * Run the migrations.
+        */
+       public function up(): void
+       {
+               Schema::table('chat_logs', function (Blueprint $table) {
+                       $table->boolean('emote_only')->default(false);
+               });
+       }
+
+       /**
+        * Reverse the migrations.
+        */
+       public function down(): void
+       {
+               Schema::table('chat_logs', function (Blueprint $table) {
+                       $table->dropColumn('emote_only');
+               });
+       }
+};
diff --git a/database/migrations/2024_09_06_090755_more_twitch_props.php b/database/migrations/2024_09_06_090755_more_twitch_props.php
new file mode 100644 (file)
index 0000000..25017c4
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+       /**
+        * Run the migrations.
+        */
+       public function up(): void
+       {
+               Schema::table('channels', function (Blueprint $table) {
+                       $table->string('twitch_category_name')->default('');
+                       $table->string('twitch_title')->default('');
+               });
+       }
+
+       /**
+        * Reverse the migrations.
+        */
+       public function down(): void
+       {
+               Schema::table('channels', function (Blueprint $table) {
+                       $table->dropColumn('twitch_category_name');
+                       $table->dropColumn('twitch_title');
+               });
+       }
+};
diff --git a/database/migrations/2025_05_07_123722_add_tournament_result_reveal_column.php b/database/migrations/2025_05_07_123722_add_tournament_result_reveal_column.php
new file mode 100644 (file)
index 0000000..5c60b81
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+       /**
+        * Run the migrations.
+        */
+       public function up(): void
+       {
+               Schema::table('tournaments', function(Blueprint $table) {
+                       $table->string('result_reveal')->default('finishers');
+               });
+       }
+
+       /**
+        * Reverse the migrations.
+        */
+       public function down(): void
+       {
+               Schema::table('tournaments', function(Blueprint $table) {
+                       $table->dropColumn('result_reveal');
+               });
+       }
+};
diff --git a/database/migrations/2025_05_19_162331_create_step_ladder_modes_table.php b/database/migrations/2025_05_19_162331_create_step_ladder_modes_table.php
new file mode 100644 (file)
index 0000000..9474c61
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+       /**
+        * Run the migrations.
+        */
+       public function up(): void
+       {
+               Schema::create('step_ladder_modes', function (Blueprint $table) {
+                       $table->id();
+                       $table->string('ext_id');
+                       $table->string('name');
+                       $table->timestamps();
+                       $table->timestamp('last_sync')->nullable()->default(null);
+               });
+       }
+
+       /**
+        * Reverse the migrations.
+        */
+       public function down(): void
+       {
+               Schema::dropIfExists('step_ladder_modes');
+       }
+};
diff --git a/database/migrations/2025_05_21_104956_tournament_description.php b/database/migrations/2025_05_21_104956_tournament_description.php
new file mode 100644 (file)
index 0000000..8adb972
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+       /**
+        * Run the migrations.
+        */
+       public function up(): void
+       {
+               Schema::table('tournaments', function(Blueprint $table) {
+                       $table->foreignId('description_id')->nullable()->default(null)->references('id')->on('techniques')->constrained();
+               });
+       }
+
+       /**
+        * Reverse the migrations.
+        */
+       public function down(): void
+       {
+               Schema::table('tournaments', function(Blueprint $table) {
+                       $table->dropForeign(['description_id']);
+                       $table->dropColumn('description_id');
+               });
+       }
+};
diff --git a/database/migrations/2025_07_02_095525_link_discord_bot_commands_and_guilds.php b/database/migrations/2025_07_02_095525_link_discord_bot_commands_and_guilds.php
new file mode 100644 (file)
index 0000000..31c7815
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+               Schema::table('discord_bot_commands', function (Blueprint $table) {
+                       $table->foreignId('discord_guild_id')->nullable()->default(null)->constrained();
+               });
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+               Schema::table('discord_bot_commands', function (Blueprint $table) {
+                       $table->dropColumn('discord_guild_id');
+               });
+    }
+};
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644 (file)
index 0000000..7214e21
--- /dev/null
@@ -0,0 +1,40 @@
+import { defineConfig } from 'eslint/config';
+import js from '@eslint/js';
+import react from 'eslint-plugin-react';
+import globals from 'globals';
+
+export default defineConfig([
+    {
+               extends: [
+                       js.configs.recommended,
+                       react.configs.flat.recommended,
+               ],
+
+               files: ['resources/js/**/*.{js,jsx}'],
+
+        plugins: {
+            react,
+        },
+
+        settings: {
+            react: {
+                version: "detect",
+            },
+        },
+
+        languageOptions: {
+            globals: {
+                ...globals.browser,
+            },
+
+            ecmaVersion: 12,
+            sourceType: "module",
+
+            parserOptions: {
+                ecmaFeatures: {
+                    jsx: true,
+                },
+            },
+        },
+    },
+]);
index e86ecd003a4ff28486abf780e7b24054a75fa814..b8998a22631720801544303692fffd745ba50e85 100644 (file)
@@ -1,6 +1,6 @@
 {
     "name": "alttp",
 {
     "name": "alttp",
-    "lockfileVersion": 2,
+    "lockfileVersion": 3,
     "requires": true,
     "packages": {
         "": {
     "requires": true,
     "packages": {
         "": {
@@ -18,9 +18,9 @@
                 "d3-drag": "^3.0.0",
                 "file-saver": "^2.0.5",
                 "formik": "^2.2.9",
                 "d3-drag": "^3.0.0",
                 "file-saver": "^2.0.5",
                 "formik": "^2.2.9",
-                "i18next": "^23.4.9",
-                "i18next-browser-languagedetector": "^7.1.0",
-                "laravel-echo": "^1.11.3",
+                "fuzzy-search": "^3.2.1",
+                "i18next-browser-languagedetector": "^8.0.0",
+                "laravel-echo": "^1.16.1",
                 "localforage": "^1.10.0",
                 "moment": "^2.29.1",
                 "numeral": "^2.0.6",
                 "localforage": "^1.10.0",
                 "moment": "^2.29.1",
                 "numeral": "^2.0.6",
@@ -29,7 +29,7 @@
                 "qs": "^6.10.3",
                 "react-bootstrap": "^2.2.0",
                 "react-helmet": "^6.1.0",
                 "qs": "^6.10.3",
                 "react-bootstrap": "^2.2.0",
                 "react-helmet": "^6.1.0",
-                "react-i18next": "^13.2.2",
+                "react-i18next": "^15.0.1",
                 "react-router-bootstrap": "^0.26.0",
                 "react-router-dom": "^6.2.2",
                 "recharts": "^2.1.9",
                 "react-router-bootstrap": "^0.26.0",
                 "react-router-dom": "^6.2.2",
                 "recharts": "^2.1.9",
                 "@popperjs/core": "^2.10.2",
                 "@tailwindcss/forms": "^0.5.6",
                 "@testing-library/jest-dom": "^6.4.2",
                 "@popperjs/core": "^2.10.2",
                 "@tailwindcss/forms": "^0.5.6",
                 "@testing-library/jest-dom": "^6.4.2",
-                "@testing-library/react": "^14.2.1",
+                "@testing-library/react": "^16.3.0",
+                "@vitejs/plugin-react": "^4.5.2",
+                "@vitest/coverage-v8": "^3.2.4",
                 "alpinejs": "^3.4.2",
                 "autoprefixer": "^10.4.2",
                 "axios": "^1.5.0",
                 "alpinejs": "^3.4.2",
                 "autoprefixer": "^10.4.2",
                 "axios": "^1.5.0",
-                "babel-jest": "^29.7.0",
                 "bootstrap": "^5.1.3",
                 "bootstrap": "^5.1.3",
-                "eslint": "^8.10.0",
+                "eslint": "^9.29.0",
                 "eslint-plugin-import": "^2.25.4",
                 "eslint-plugin-react": "^7.29.3",
                 "eslint-plugin-import": "^2.25.4",
                 "eslint-plugin-react": "^7.29.3",
-                "jest": "^29.7.0",
-                "jest-environment-jsdom": "^29.7.0",
+                "globals": "^16.2.0",
+                "i18next": "^25.2.1",
+                "jsdom": "^26.1.0",
                 "laravel-mix": "^6.0.6",
                 "laravel-mix": "^6.0.6",
+                "laravel-vite-plugin": "^1.3.0",
                 "lodash": "^4.17.19",
                 "postcss": "^8.4.6",
                 "lodash": "^4.17.19",
                 "postcss": "^8.4.6",
-                "postcss-import": "^15.1.0",
-                "react": "^18.2.0",
-                "react-dom": "^18.2.0",
+                "react": "19.1.0",
+                "react-dom": "19.1.0",
                 "resolve-url-loader": "^5.0.0",
                 "sass": "^1.32.11",
                 "resolve-url-loader": "^5.0.0",
                 "sass": "^1.32.11",
-                "sass-loader": "^13.3.2",
-                "tailwindcss": "^3.0.18"
-            }
-        },
-        "node_modules/@aashutoshrathi/word-wrap": {
-            "version": "1.2.6",
-            "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
-            "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.10.0"
+                "vite": "^6.3.5",
+                "vite-plugin-webpackchunkname": "^1.0.3",
+                "vitest": "^3.2.4"
             }
         },
         "node_modules/@adobe/css-tools": {
             }
         },
         "node_modules/@adobe/css-tools": {
-            "version": "4.3.3",
-            "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz",
-            "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==",
-            "dev": true
+            "version": "4.4.3",
+            "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.3.tgz",
+            "integrity": "sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==",
+            "dev": true,
+            "license": "MIT"
         },
         "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==",
             "dev": true,
         },
         "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==",
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "engines": {
                 "node": ">=10"
             },
             "engines": {
                 "node": ">=10"
             },
             }
         },
         "node_modules/@ampproject/remapping": {
             }
         },
         "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==",
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+            "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
-                "@jridgewell/gen-mapping": "^0.3.0",
-                "@jridgewell/trace-mapping": "^0.3.9"
+                "@jridgewell/gen-mapping": "^0.3.5",
+                "@jridgewell/trace-mapping": "^0.3.24"
             },
             "engines": {
                 "node": ">=6.0.0"
             }
         },
             },
             "engines": {
                 "node": ">=6.0.0"
             }
         },
+        "node_modules/@asamuzakjp/css-color": {
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz",
+            "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@csstools/css-calc": "^2.1.3",
+                "@csstools/css-color-parser": "^3.0.9",
+                "@csstools/css-parser-algorithms": "^3.0.4",
+                "@csstools/css-tokenizer": "^3.0.3",
+                "lru-cache": "^10.4.3"
+            }
+        },
+        "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": {
+            "version": "10.4.3",
+            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+            "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+            "dev": true,
+            "license": "ISC"
+        },
         "node_modules/@babel/code-frame": {
         "node_modules/@babel/code-frame": {
-            "version": "7.23.5",
-            "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
-            "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+            "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/highlight": "^7.23.4",
-                "chalk": "^2.4.2"
+                "@babel/helper-validator-identifier": "^7.27.1",
+                "js-tokens": "^4.0.0",
+                "picocolors": "^1.1.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/compat-data": {
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/compat-data": {
-            "version": "7.23.5",
-            "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz",
-            "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==",
+            "version": "7.27.5",
+            "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.5.tgz",
+            "integrity": "sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/core": {
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/core": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz",
-            "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==",
+            "version": "7.27.4",
+            "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.4.tgz",
+            "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@ampproject/remapping": "^2.2.0",
             "dependencies": {
                 "@ampproject/remapping": "^2.2.0",
-                "@babel/code-frame": "^7.23.5",
-                "@babel/generator": "^7.23.6",
-                "@babel/helper-compilation-targets": "^7.23.6",
-                "@babel/helper-module-transforms": "^7.23.3",
-                "@babel/helpers": "^7.23.9",
-                "@babel/parser": "^7.23.9",
-                "@babel/template": "^7.23.9",
-                "@babel/traverse": "^7.23.9",
-                "@babel/types": "^7.23.9",
+                "@babel/code-frame": "^7.27.1",
+                "@babel/generator": "^7.27.3",
+                "@babel/helper-compilation-targets": "^7.27.2",
+                "@babel/helper-module-transforms": "^7.27.3",
+                "@babel/helpers": "^7.27.4",
+                "@babel/parser": "^7.27.4",
+                "@babel/template": "^7.27.2",
+                "@babel/traverse": "^7.27.4",
+                "@babel/types": "^7.27.3",
                 "convert-source-map": "^2.0.0",
                 "debug": "^4.1.0",
                 "gensync": "^1.0.0-beta.2",
                 "convert-source-map": "^2.0.0",
                 "debug": "^4.1.0",
                 "gensync": "^1.0.0-beta.2",
                 "url": "https://opencollective.com/babel"
             }
         },
                 "url": "https://opencollective.com/babel"
             }
         },
-        "node_modules/@babel/core/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==",
-            "dev": true
-        },
         "node_modules/@babel/eslint-parser": {
         "node_modules/@babel/eslint-parser": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.15.tgz",
-            "integrity": "sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg==",
+            "version": "7.27.5",
+            "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.5.tgz",
+            "integrity": "sha512-HLkYQfRICudzcOtjGwkPvGc5nF1b4ljLZh1IRDj50lRZ718NAKVgQpIAUX8bfg6u/yuSKY3L7E0YzIV+OxrB8Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
                 "eslint-visitor-keys": "^2.1.0",
             "dependencies": {
                 "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
                 "eslint-visitor-keys": "^2.1.0",
             },
             "peerDependencies": {
                 "@babel/core": "^7.11.0",
             },
             "peerDependencies": {
                 "@babel/core": "^7.11.0",
-                "eslint": "^7.5.0 || ^8.0.0"
+                "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0"
             }
         },
         "node_modules/@babel/generator": {
             }
         },
         "node_modules/@babel/generator": {
-            "version": "7.23.6",
-            "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
-            "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
+            "version": "7.27.5",
+            "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz",
+            "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/types": "^7.23.6",
-                "@jridgewell/gen-mapping": "^0.3.2",
-                "@jridgewell/trace-mapping": "^0.3.17",
-                "jsesc": "^2.5.1"
+                "@babel/parser": "^7.27.5",
+                "@babel/types": "^7.27.3",
+                "@jridgewell/gen-mapping": "^0.3.5",
+                "@jridgewell/trace-mapping": "^0.3.25",
+                "jsesc": "^3.0.2"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-annotate-as-pure": {
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-annotate-as-pure": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
-            "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/types": "^7.22.5"
-            },
-            "engines": {
-                "node": ">=6.9.0"
-            }
-        },
-        "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz",
-            "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==",
+            "version": "7.27.3",
+            "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
+            "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/types": "^7.22.15"
+                "@babel/types": "^7.27.3"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-compilation-targets": {
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-compilation-targets": {
-            "version": "7.23.6",
-            "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz",
-            "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==",
+            "version": "7.27.2",
+            "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+            "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/compat-data": "^7.23.5",
-                "@babel/helper-validator-option": "^7.23.5",
-                "browserslist": "^4.22.2",
+                "@babel/compat-data": "^7.27.2",
+                "@babel/helper-validator-option": "^7.27.1",
+                "browserslist": "^4.24.0",
                 "lru-cache": "^5.1.1",
                 "semver": "^6.3.1"
             },
                 "lru-cache": "^5.1.1",
                 "semver": "^6.3.1"
             },
             }
         },
         "node_modules/@babel/helper-create-class-features-plugin": {
             }
         },
         "node_modules/@babel/helper-create-class-features-plugin": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz",
-            "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-function-name": "^7.22.5",
-                "@babel/helper-member-expression-to-functions": "^7.22.15",
-                "@babel/helper-optimise-call-expression": "^7.22.5",
-                "@babel/helper-replace-supers": "^7.22.9",
-                "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
-                "@babel/helper-split-export-declaration": "^7.22.6",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz",
+            "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/helper-annotate-as-pure": "^7.27.1",
+                "@babel/helper-member-expression-to-functions": "^7.27.1",
+                "@babel/helper-optimise-call-expression": "^7.27.1",
+                "@babel/helper-replace-supers": "^7.27.1",
+                "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+                "@babel/traverse": "^7.27.1",
                 "semver": "^6.3.1"
             },
             "engines": {
                 "semver": "^6.3.1"
             },
             "engines": {
             }
         },
         "node_modules/@babel/helper-create-regexp-features-plugin": {
             }
         },
         "node_modules/@babel/helper-create-regexp-features-plugin": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz",
-            "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz",
+            "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "regexpu-core": "^5.3.1",
+                "@babel/helper-annotate-as-pure": "^7.27.1",
+                "regexpu-core": "^6.2.0",
                 "semver": "^6.3.1"
             },
             "engines": {
                 "semver": "^6.3.1"
             },
             "engines": {
             }
         },
         "node_modules/@babel/helper-define-polyfill-provider": {
             }
         },
         "node_modules/@babel/helper-define-polyfill-provider": {
-            "version": "0.4.2",
-            "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz",
-            "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==",
+            "version": "0.6.4",
+            "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz",
+            "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/helper-compilation-targets": "^7.22.6",
                 "@babel/helper-plugin-utils": "^7.22.5",
             "dependencies": {
                 "@babel/helper-compilation-targets": "^7.22.6",
                 "@babel/helper-plugin-utils": "^7.22.5",
                 "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
             }
         },
                 "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.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==",
-            "dev": true,
-            "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==",
-            "dev": true,
-            "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==",
-            "dev": true,
-            "dependencies": {
-                "@babel/types": "^7.22.5"
-            },
-            "engines": {
-                "node": ">=6.9.0"
-            }
-        },
         "node_modules/@babel/helper-member-expression-to-functions": {
         "node_modules/@babel/helper-member-expression-to-functions": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz",
-            "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz",
+            "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/types": "^7.22.15"
+                "@babel/traverse": "^7.27.1",
+                "@babel/types": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-module-imports": {
             },
             "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==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+            "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/types": "^7.22.15"
+                "@babel/traverse": "^7.27.1",
+                "@babel/types": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-module-transforms": {
             },
             "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==",
+            "version": "7.27.3",
+            "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz",
+            "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "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-module-imports": "^7.27.1",
+                "@babel/helper-validator-identifier": "^7.27.1",
+                "@babel/traverse": "^7.27.3"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-optimise-call-expression": {
             }
         },
         "node_modules/@babel/helper-optimise-call-expression": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz",
-            "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz",
+            "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/types": "^7.22.5"
+                "@babel/types": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-plugin-utils": {
             },
             "engines": {
                 "node": ">=6.9.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==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+            "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-remap-async-to-generator": {
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-remap-async-to-generator": {
-            "version": "7.22.9",
-            "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz",
-            "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz",
+            "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-wrap-function": "^7.22.9"
+                "@babel/helper-annotate-as-pure": "^7.27.1",
+                "@babel/helper-wrap-function": "^7.27.1",
+                "@babel/traverse": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-replace-supers": {
             }
         },
         "node_modules/@babel/helper-replace-supers": {
-            "version": "7.22.9",
-            "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz",
-            "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz",
+            "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-member-expression-to-functions": "^7.22.5",
-                "@babel/helper-optimise-call-expression": "^7.22.5"
+                "@babel/helper-member-expression-to-functions": "^7.27.1",
+                "@babel/helper-optimise-call-expression": "^7.27.1",
+                "@babel/traverse": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
                 "@babel/core": "^7.0.0"
             }
         },
                 "@babel/core": "^7.0.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==",
-            "dev": true,
-            "dependencies": {
-                "@babel/types": "^7.22.5"
-            },
-            "engines": {
-                "node": ">=6.9.0"
-            }
-        },
         "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
         "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz",
-            "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==",
-            "dev": true,
-            "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==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz",
+            "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/types": "^7.22.5"
+                "@babel/traverse": "^7.27.1",
+                "@babel/types": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-string-parser": {
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-string-parser": {
-            "version": "7.23.4",
-            "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
-            "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+            "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-validator-identifier": {
             "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==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+            "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-validator-option": {
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-validator-option": {
-            "version": "7.23.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
-            "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+            "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-wrap-function": {
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helper-wrap-function": {
-            "version": "7.22.10",
-            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz",
-            "integrity": "sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz",
+            "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-function-name": "^7.22.5",
-                "@babel/template": "^7.22.5",
-                "@babel/types": "^7.22.10"
+                "@babel/template": "^7.27.1",
+                "@babel/traverse": "^7.27.1",
+                "@babel/types": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helpers": {
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/helpers": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz",
-            "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==",
+            "version": "7.27.6",
+            "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.6.tgz",
+            "integrity": "sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/template": "^7.23.9",
-                "@babel/traverse": "^7.23.9",
-                "@babel/types": "^7.23.9"
+                "@babel/template": "^7.27.2",
+                "@babel/types": "^7.27.6"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
-        "node_modules/@babel/highlight": {
-            "version": "7.23.4",
-            "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
-            "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
+        "node_modules/@babel/parser": {
+            "version": "7.27.5",
+            "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz",
+            "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-validator-identifier": "^7.22.20",
-                "chalk": "^2.4.2",
-                "js-tokens": "^4.0.0"
+                "@babel/types": "^7.27.3"
             },
             },
-            "engines": {
-                "node": ">=6.9.0"
-            }
-        },
-        "node_modules/@babel/parser": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
-            "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
-            "dev": true,
             "bin": {
                 "parser": "bin/babel-parser.js"
             },
             "bin": {
                 "parser": "bin/babel-parser.js"
             },
                 "node": ">=6.0.0"
             }
         },
                 "node": ">=6.0.0"
             }
         },
-        "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz",
-            "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==",
+        "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz",
+            "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/traverse": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
                 "@babel/core": "^7.0.0"
             }
         },
                 "@babel/core": "^7.0.0"
             }
         },
-        "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz",
-            "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==",
+        "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz",
+            "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
-                "@babel/plugin-transform-optional-chaining": "^7.22.15"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "peerDependencies": {
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "peerDependencies": {
-                "@babel/core": "^7.13.0"
+                "@babel/core": "^7.0.0"
             }
         },
             }
         },
-        "node_modules/@babel/plugin-proposal-object-rest-spread": {
-            "version": "7.20.7",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz",
-            "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==",
-            "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.",
+        "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz",
+            "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/compat-data": "^7.20.5",
-                "@babel/helper-compilation-targets": "^7.20.7",
-                "@babel/helper-plugin-utils": "^7.20.2",
-                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-                "@babel/plugin-transform-parameters": "^7.20.7"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "peerDependencies": {
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
+                "@babel/core": "^7.0.0"
             }
         },
             }
         },
-        "node_modules/@babel/plugin-proposal-private-property-in-object": {
-            "version": "7.21.0-placeholder-for-preset-env.2",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
-            "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
+        "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz",
+            "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+                "@babel/plugin-transform-optional-chaining": "^7.27.1"
+            },
             "engines": {
                 "node": ">=6.9.0"
             },
             "peerDependencies": {
             "engines": {
                 "node": ">=6.9.0"
             },
             "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
+                "@babel/core": "^7.13.0"
             }
         },
             }
         },
-        "node_modules/@babel/plugin-syntax-async-generators": {
-            "version": "7.8.4",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
-            "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+        "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz",
+            "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.8.0"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/traverse": "^7.27.1"
             },
             },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
-        "node_modules/@babel/plugin-syntax-bigint": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
-            "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.8.0"
+            "engines": {
+                "node": ">=6.9.0"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
+                "@babel/core": "^7.0.0"
             }
         },
             }
         },
-        "node_modules/@babel/plugin-syntax-class-properties": {
-            "version": "7.12.13",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
-            "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+        "node_modules/@babel/plugin-proposal-object-rest-spread": {
+            "version": "7.20.7",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz",
+            "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==",
+            "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.12.13"
+                "@babel/compat-data": "^7.20.5",
+                "@babel/helper-compilation-targets": "^7.20.7",
+                "@babel/helper-plugin-utils": "^7.20.2",
+                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+                "@babel/plugin-transform-parameters": "^7.20.7"
+            },
+            "engines": {
+                "node": ">=6.9.0"
             },
             "peerDependencies": {
                 "@babel/core": "^7.0.0-0"
             }
         },
             },
             "peerDependencies": {
                 "@babel/core": "^7.0.0-0"
             }
         },
-        "node_modules/@babel/plugin-syntax-class-static-block": {
-            "version": "7.14.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
-            "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+        "node_modules/@babel/plugin-proposal-private-property-in-object": {
+            "version": "7.21.0-placeholder-for-preset-env.2",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
+            "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.14.5"
-            },
+            "license": "MIT",
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
             "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
             "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/helper-plugin-utils": "^7.8.0"
             },
             "dependencies": {
                 "@babel/helper-plugin-utils": "^7.8.0"
             },
                 "@babel/core": "^7.0.0-0"
             }
         },
                 "@babel/core": "^7.0.0-0"
             }
         },
-        "node_modules/@babel/plugin-syntax-export-namespace-from": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
-            "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.8.3"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
         "node_modules/@babel/plugin-syntax-import-assertions": {
         "node_modules/@babel/plugin-syntax-import-assertions": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz",
-            "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz",
+            "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-syntax-import-attributes": {
             }
         },
         "node_modules/@babel/plugin-syntax-import-attributes": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz",
-            "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz",
+            "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
                 "@babel/core": "^7.0.0-0"
             }
         },
                 "@babel/core": "^7.0.0-0"
             }
         },
-        "node_modules/@babel/plugin-syntax-import-meta": {
-            "version": "7.10.4",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
-            "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.10.4"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
-        "node_modules/@babel/plugin-syntax-json-strings": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
-            "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
         "node_modules/@babel/plugin-syntax-jsx": {
         "node_modules/@babel/plugin-syntax-jsx": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
-            "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
+            "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
                 "@babel/core": "^7.0.0-0"
             }
         },
                 "@babel/core": "^7.0.0-0"
             }
         },
-        "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
-            "version": "7.10.4",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
-            "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.10.4"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
-        "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
-            "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
-        "node_modules/@babel/plugin-syntax-numeric-separator": {
-            "version": "7.10.4",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
-            "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.10.4"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
         "node_modules/@babel/plugin-syntax-object-rest-spread": {
             "version": "7.8.3",
             "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
             "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
             "dev": true,
         "node_modules/@babel/plugin-syntax-object-rest-spread": {
             "version": "7.8.3",
             "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
             "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/helper-plugin-utils": "^7.8.0"
             },
             "dependencies": {
                 "@babel/helper-plugin-utils": "^7.8.0"
             },
                 "@babel/core": "^7.0.0-0"
             }
         },
                 "@babel/core": "^7.0.0-0"
             }
         },
-        "node_modules/@babel/plugin-syntax-optional-catch-binding": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
-            "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
-        "node_modules/@babel/plugin-syntax-optional-chaining": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
-            "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
-        "node_modules/@babel/plugin-syntax-private-property-in-object": {
-            "version": "7.14.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
-            "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.14.5"
-            },
-            "engines": {
-                "node": ">=6.9.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
-        "node_modules/@babel/plugin-syntax-top-level-await": {
-            "version": "7.14.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
-            "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.14.5"
-            },
-            "engines": {
-                "node": ">=6.9.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
-        "node_modules/@babel/plugin-syntax-typescript": {
-            "version": "7.23.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz",
-            "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            },
-            "engines": {
-                "node": ">=6.9.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0-0"
-            }
-        },
         "node_modules/@babel/plugin-syntax-unicode-sets-regex": {
             "version": "7.18.6",
             "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
             "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
             "dev": true,
         "node_modules/@babel/plugin-syntax-unicode-sets-regex": {
             "version": "7.18.6",
             "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
             "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/helper-create-regexp-features-plugin": "^7.18.6",
                 "@babel/helper-plugin-utils": "^7.18.6"
             "dependencies": {
                 "@babel/helper-create-regexp-features-plugin": "^7.18.6",
                 "@babel/helper-plugin-utils": "^7.18.6"
             }
         },
         "node_modules/@babel/plugin-transform-arrow-functions": {
             }
         },
         "node_modules/@babel/plugin-transform-arrow-functions": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz",
-            "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz",
+            "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-async-generator-functions": {
             }
         },
         "node_modules/@babel/plugin-transform-async-generator-functions": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz",
-            "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz",
+            "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-remap-async-to-generator": "^7.22.9",
-                "@babel/plugin-syntax-async-generators": "^7.8.4"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-remap-async-to-generator": "^7.27.1",
+                "@babel/traverse": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-async-to-generator": {
             }
         },
         "node_modules/@babel/plugin-transform-async-to-generator": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz",
-            "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz",
+            "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-module-imports": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-remap-async-to-generator": "^7.22.5"
+                "@babel/helper-module-imports": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-remap-async-to-generator": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-block-scoped-functions": {
             }
         },
         "node_modules/@babel/plugin-transform-block-scoped-functions": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz",
-            "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz",
+            "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-block-scoping": {
             }
         },
         "node_modules/@babel/plugin-transform-block-scoping": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz",
-            "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==",
+            "version": "7.27.5",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.5.tgz",
+            "integrity": "sha512-JF6uE2s67f0y2RZcm2kpAUEbD50vH62TyWVebxwHAlbSdM49VqPz8t4a1uIjp4NIOIZ4xzLfjY5emt/RCyC7TQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-class-properties": {
             }
         },
         "node_modules/@babel/plugin-transform-class-properties": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz",
-            "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz",
+            "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-create-class-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-create-class-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-class-static-block": {
             }
         },
         "node_modules/@babel/plugin-transform-class-static-block": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz",
-            "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz",
+            "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-create-class-features-plugin": "^7.22.11",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-class-static-block": "^7.14.5"
+                "@babel/helper-create-class-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-classes": {
             }
         },
         "node_modules/@babel/plugin-transform-classes": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz",
-            "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz",
+            "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-compilation-targets": "^7.22.15",
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-function-name": "^7.22.5",
-                "@babel/helper-optimise-call-expression": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-replace-supers": "^7.22.9",
-                "@babel/helper-split-export-declaration": "^7.22.6",
+                "@babel/helper-annotate-as-pure": "^7.27.1",
+                "@babel/helper-compilation-targets": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-replace-supers": "^7.27.1",
+                "@babel/traverse": "^7.27.1",
                 "globals": "^11.1.0"
             },
             "engines": {
                 "globals": "^11.1.0"
             },
             "engines": {
                 "@babel/core": "^7.0.0-0"
             }
         },
                 "@babel/core": "^7.0.0-0"
             }
         },
+        "node_modules/@babel/plugin-transform-classes/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==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
+        },
         "node_modules/@babel/plugin-transform-computed-properties": {
         "node_modules/@babel/plugin-transform-computed-properties": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz",
-            "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz",
+            "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/template": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/template": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-destructuring": {
             }
         },
         "node_modules/@babel/plugin-transform-destructuring": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz",
-            "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==",
+            "version": "7.27.3",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.3.tgz",
+            "integrity": "sha512-s4Jrok82JpiaIprtY2nHsYmrThKvvwgHwjgd7UMiYhZaN0asdXNLr0y+NjTfkA7SyQE5i2Fb7eawUOZmLvyqOA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-dotall-regex": {
             }
         },
         "node_modules/@babel/plugin-transform-dotall-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz",
-            "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz",
+            "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-duplicate-keys": {
             }
         },
         "node_modules/@babel/plugin-transform-duplicate-keys": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz",
-            "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz",
+            "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
                 "@babel/core": "^7.0.0-0"
             }
         },
                 "@babel/core": "^7.0.0-0"
             }
         },
+        "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz",
+            "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
+            },
+            "engines": {
+                "node": ">=6.9.0"
+            },
+            "peerDependencies": {
+                "@babel/core": "^7.0.0"
+            }
+        },
         "node_modules/@babel/plugin-transform-dynamic-import": {
         "node_modules/@babel/plugin-transform-dynamic-import": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz",
-            "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz",
+            "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-dynamic-import": "^7.8.3"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-exponentiation-operator": {
             }
         },
         "node_modules/@babel/plugin-transform-exponentiation-operator": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz",
-            "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz",
+            "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-export-namespace-from": {
             }
         },
         "node_modules/@babel/plugin-transform-export-namespace-from": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz",
-            "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz",
+            "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-for-of": {
             }
         },
         "node_modules/@babel/plugin-transform-for-of": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz",
-            "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz",
+            "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-function-name": {
             }
         },
         "node_modules/@babel/plugin-transform-function-name": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz",
-            "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz",
+            "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-compilation-targets": "^7.22.5",
-                "@babel/helper-function-name": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-compilation-targets": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/traverse": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-json-strings": {
             }
         },
         "node_modules/@babel/plugin-transform-json-strings": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz",
-            "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz",
+            "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-json-strings": "^7.8.3"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-literals": {
             }
         },
         "node_modules/@babel/plugin-transform-literals": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz",
-            "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz",
+            "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-logical-assignment-operators": {
             }
         },
         "node_modules/@babel/plugin-transform-logical-assignment-operators": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz",
-            "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz",
+            "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-member-expression-literals": {
             }
         },
         "node_modules/@babel/plugin-transform-member-expression-literals": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz",
-            "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz",
+            "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-modules-amd": {
             }
         },
         "node_modules/@babel/plugin-transform-modules-amd": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz",
-            "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz",
+            "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-module-transforms": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-module-transforms": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-modules-commonjs": {
             }
         },
         "node_modules/@babel/plugin-transform-modules-commonjs": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz",
-            "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz",
+            "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-module-transforms": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-simple-access": "^7.22.5"
+                "@babel/helper-module-transforms": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-modules-systemjs": {
             }
         },
         "node_modules/@babel/plugin-transform-modules-systemjs": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz",
-            "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz",
+            "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-hoist-variables": "^7.22.5",
-                "@babel/helper-module-transforms": "^7.22.9",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-validator-identifier": "^7.22.5"
+                "@babel/helper-module-transforms": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-validator-identifier": "^7.27.1",
+                "@babel/traverse": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-modules-umd": {
             }
         },
         "node_modules/@babel/plugin-transform-modules-umd": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz",
-            "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz",
+            "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-module-transforms": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-module-transforms": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
             }
         },
         "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz",
-            "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz",
+            "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-new-target": {
             }
         },
         "node_modules/@babel/plugin-transform-new-target": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz",
-            "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz",
+            "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
             }
         },
         "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz",
-            "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz",
+            "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-numeric-separator": {
             }
         },
         "node_modules/@babel/plugin-transform-numeric-separator": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz",
-            "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz",
+            "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-numeric-separator": "^7.10.4"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-object-rest-spread": {
             }
         },
         "node_modules/@babel/plugin-transform-object-rest-spread": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz",
-            "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==",
+            "version": "7.27.3",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.3.tgz",
+            "integrity": "sha512-7ZZtznF9g4l2JCImCo5LNKFHB5eXnN39lLtLY5Tg+VkR0jwOt7TBciMckuiQIOIW7L5tkQOCh3bVGYeXgMx52Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/compat-data": "^7.22.9",
-                "@babel/helper-compilation-targets": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-                "@babel/plugin-transform-parameters": "^7.22.15"
+                "@babel/helper-compilation-targets": "^7.27.2",
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/plugin-transform-destructuring": "^7.27.3",
+                "@babel/plugin-transform-parameters": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-object-super": {
             }
         },
         "node_modules/@babel/plugin-transform-object-super": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz",
-            "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz",
+            "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-replace-supers": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-replace-supers": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-optional-catch-binding": {
             }
         },
         "node_modules/@babel/plugin-transform-optional-catch-binding": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz",
-            "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz",
+            "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-optional-chaining": {
             }
         },
         "node_modules/@babel/plugin-transform-optional-chaining": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz",
-            "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz",
+            "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
-                "@babel/plugin-syntax-optional-chaining": "^7.8.3"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-parameters": {
             }
         },
         "node_modules/@babel/plugin-transform-parameters": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz",
-            "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz",
+            "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-private-methods": {
             }
         },
         "node_modules/@babel/plugin-transform-private-methods": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz",
-            "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz",
+            "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-create-class-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-create-class-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-private-property-in-object": {
             }
         },
         "node_modules/@babel/plugin-transform-private-property-in-object": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz",
-            "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz",
+            "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-create-class-features-plugin": "^7.22.11",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
+                "@babel/helper-annotate-as-pure": "^7.27.1",
+                "@babel/helper-create-class-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-property-literals": {
             }
         },
         "node_modules/@babel/plugin-transform-property-literals": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz",
-            "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz",
+            "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-react-display-name": {
             }
         },
         "node_modules/@babel/plugin-transform-react-display-name": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz",
-            "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.27.1.tgz",
+            "integrity": "sha512-p9+Vl3yuHPmkirRrg021XiP+EETmPMQTLr6Ayjj85RLNEbb3Eya/4VI0vAdzQG9SEAl2Lnt7fy5lZyMzjYoZQQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-react-jsx": {
             }
         },
         "node_modules/@babel/plugin-transform-react-jsx": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz",
-            "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz",
+            "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-module-imports": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-jsx": "^7.22.5",
-                "@babel/types": "^7.22.15"
+                "@babel/helper-annotate-as-pure": "^7.27.1",
+                "@babel/helper-module-imports": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/plugin-syntax-jsx": "^7.27.1",
+                "@babel/types": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-react-jsx-development": {
             }
         },
         "node_modules/@babel/plugin-transform-react-jsx-development": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz",
-            "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz",
+            "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/plugin-transform-react-jsx": "^7.27.1"
+            },
+            "engines": {
+                "node": ">=6.9.0"
+            },
+            "peerDependencies": {
+                "@babel/core": "^7.0.0-0"
+            }
+        },
+        "node_modules/@babel/plugin-transform-react-jsx-self": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
+            "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/helper-plugin-utils": "^7.27.1"
+            },
+            "engines": {
+                "node": ">=6.9.0"
+            },
+            "peerDependencies": {
+                "@babel/core": "^7.0.0-0"
+            }
+        },
+        "node_modules/@babel/plugin-transform-react-jsx-source": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
+            "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/plugin-transform-react-jsx": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-react-pure-annotations": {
             }
         },
         "node_modules/@babel/plugin-transform-react-pure-annotations": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz",
-            "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz",
+            "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-annotate-as-pure": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-regenerator": {
             }
         },
         "node_modules/@babel/plugin-transform-regenerator": {
-            "version": "7.22.10",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz",
-            "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==",
+            "version": "7.27.5",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.5.tgz",
+            "integrity": "sha512-uhB8yHerfe3MWnuLAhEbeQ4afVoqv8BQsPqrTv7e/jZ9y00kJL6l9a/f4OWaKxotmjzewfEyXE1vgDJenkQ2/Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "regenerator-transform": "^0.15.2"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
                 "@babel/core": "^7.0.0-0"
             }
         },
                 "@babel/core": "^7.0.0-0"
             }
         },
+        "node_modules/@babel/plugin-transform-regexp-modifiers": {
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz",
+            "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
+            },
+            "engines": {
+                "node": ">=6.9.0"
+            },
+            "peerDependencies": {
+                "@babel/core": "^7.0.0"
+            }
+        },
         "node_modules/@babel/plugin-transform-reserved-words": {
         "node_modules/@babel/plugin-transform-reserved-words": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz",
-            "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz",
+            "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-runtime": {
             }
         },
         "node_modules/@babel/plugin-transform-runtime": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.15.tgz",
-            "integrity": "sha512-tEVLhk8NRZSmwQ0DJtxxhTrCht1HVo8VaMzYT4w6lwyKBuHsgoioAUA7/6eT2fRfc5/23fuGdlwIxXhRVgWr4g==",
+            "version": "7.27.4",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.27.4.tgz",
+            "integrity": "sha512-D68nR5zxU64EUzV8i7T3R5XP0Xhrou/amNnddsRQssx6GrTLdZl1rLxyjtVZBd+v/NVX4AbTPOB5aU8thAZV1A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-module-imports": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "babel-plugin-polyfill-corejs2": "^0.4.5",
-                "babel-plugin-polyfill-corejs3": "^0.8.3",
-                "babel-plugin-polyfill-regenerator": "^0.5.2",
+                "@babel/helper-module-imports": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "babel-plugin-polyfill-corejs2": "^0.4.10",
+                "babel-plugin-polyfill-corejs3": "^0.11.0",
+                "babel-plugin-polyfill-regenerator": "^0.6.1",
                 "semver": "^6.3.1"
             },
             "engines": {
                 "semver": "^6.3.1"
             },
             "engines": {
             }
         },
         "node_modules/@babel/plugin-transform-shorthand-properties": {
             }
         },
         "node_modules/@babel/plugin-transform-shorthand-properties": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz",
-            "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz",
+            "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-spread": {
             }
         },
         "node_modules/@babel/plugin-transform-spread": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz",
-            "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz",
+            "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-sticky-regex": {
             }
         },
         "node_modules/@babel/plugin-transform-sticky-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz",
-            "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz",
+            "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-template-literals": {
             }
         },
         "node_modules/@babel/plugin-transform-template-literals": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz",
-            "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz",
+            "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-typeof-symbol": {
             }
         },
         "node_modules/@babel/plugin-transform-typeof-symbol": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz",
-            "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz",
+            "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-unicode-escapes": {
             }
         },
         "node_modules/@babel/plugin-transform-unicode-escapes": {
-            "version": "7.22.10",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz",
-            "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz",
+            "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-unicode-property-regex": {
             }
         },
         "node_modules/@babel/plugin-transform-unicode-property-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz",
-            "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz",
+            "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-unicode-regex": {
             }
         },
         "node_modules/@babel/plugin-transform-unicode-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz",
-            "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz",
+            "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/plugin-transform-unicode-sets-regex": {
             }
         },
         "node_modules/@babel/plugin-transform-unicode-sets-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz",
-            "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz",
+            "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
+                "@babel/helper-create-regexp-features-plugin": "^7.27.1",
+                "@babel/helper-plugin-utils": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/preset-env": {
             }
         },
         "node_modules/@babel/preset-env": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.15.tgz",
-            "integrity": "sha512-tZFHr54GBkHk6hQuVA8w4Fmq+MSPsfvMG0vPnOYyTnJpyfMqybL8/MbNCPRT9zc2KBO2pe4tq15g6Uno4Jpoag==",
-            "dev": true,
-            "dependencies": {
-                "@babel/compat-data": "^7.22.9",
-                "@babel/helper-compilation-targets": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-validator-option": "^7.22.15",
-                "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15",
-                "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15",
+            "version": "7.27.2",
+            "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz",
+            "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/compat-data": "^7.27.2",
+                "@babel/helper-compilation-targets": "^7.27.2",
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-validator-option": "^7.27.1",
+                "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1",
+                "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1",
+                "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1",
+                "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1",
+                "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1",
                 "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
                 "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
-                "@babel/plugin-syntax-async-generators": "^7.8.4",
-                "@babel/plugin-syntax-class-properties": "^7.12.13",
-                "@babel/plugin-syntax-class-static-block": "^7.14.5",
-                "@babel/plugin-syntax-dynamic-import": "^7.8.3",
-                "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
-                "@babel/plugin-syntax-import-assertions": "^7.22.5",
-                "@babel/plugin-syntax-import-attributes": "^7.22.5",
-                "@babel/plugin-syntax-import-meta": "^7.10.4",
-                "@babel/plugin-syntax-json-strings": "^7.8.3",
-                "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
-                "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
-                "@babel/plugin-syntax-numeric-separator": "^7.10.4",
-                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-                "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
-                "@babel/plugin-syntax-optional-chaining": "^7.8.3",
-                "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
-                "@babel/plugin-syntax-top-level-await": "^7.14.5",
+                "@babel/plugin-syntax-import-assertions": "^7.27.1",
+                "@babel/plugin-syntax-import-attributes": "^7.27.1",
                 "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
                 "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
-                "@babel/plugin-transform-arrow-functions": "^7.22.5",
-                "@babel/plugin-transform-async-generator-functions": "^7.22.15",
-                "@babel/plugin-transform-async-to-generator": "^7.22.5",
-                "@babel/plugin-transform-block-scoped-functions": "^7.22.5",
-                "@babel/plugin-transform-block-scoping": "^7.22.15",
-                "@babel/plugin-transform-class-properties": "^7.22.5",
-                "@babel/plugin-transform-class-static-block": "^7.22.11",
-                "@babel/plugin-transform-classes": "^7.22.15",
-                "@babel/plugin-transform-computed-properties": "^7.22.5",
-                "@babel/plugin-transform-destructuring": "^7.22.15",
-                "@babel/plugin-transform-dotall-regex": "^7.22.5",
-                "@babel/plugin-transform-duplicate-keys": "^7.22.5",
-                "@babel/plugin-transform-dynamic-import": "^7.22.11",
-                "@babel/plugin-transform-exponentiation-operator": "^7.22.5",
-                "@babel/plugin-transform-export-namespace-from": "^7.22.11",
-                "@babel/plugin-transform-for-of": "^7.22.15",
-                "@babel/plugin-transform-function-name": "^7.22.5",
-                "@babel/plugin-transform-json-strings": "^7.22.11",
-                "@babel/plugin-transform-literals": "^7.22.5",
-                "@babel/plugin-transform-logical-assignment-operators": "^7.22.11",
-                "@babel/plugin-transform-member-expression-literals": "^7.22.5",
-                "@babel/plugin-transform-modules-amd": "^7.22.5",
-                "@babel/plugin-transform-modules-commonjs": "^7.22.15",
-                "@babel/plugin-transform-modules-systemjs": "^7.22.11",
-                "@babel/plugin-transform-modules-umd": "^7.22.5",
-                "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5",
-                "@babel/plugin-transform-new-target": "^7.22.5",
-                "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11",
-                "@babel/plugin-transform-numeric-separator": "^7.22.11",
-                "@babel/plugin-transform-object-rest-spread": "^7.22.15",
-                "@babel/plugin-transform-object-super": "^7.22.5",
-                "@babel/plugin-transform-optional-catch-binding": "^7.22.11",
-                "@babel/plugin-transform-optional-chaining": "^7.22.15",
-                "@babel/plugin-transform-parameters": "^7.22.15",
-                "@babel/plugin-transform-private-methods": "^7.22.5",
-                "@babel/plugin-transform-private-property-in-object": "^7.22.11",
-                "@babel/plugin-transform-property-literals": "^7.22.5",
-                "@babel/plugin-transform-regenerator": "^7.22.10",
-                "@babel/plugin-transform-reserved-words": "^7.22.5",
-                "@babel/plugin-transform-shorthand-properties": "^7.22.5",
-                "@babel/plugin-transform-spread": "^7.22.5",
-                "@babel/plugin-transform-sticky-regex": "^7.22.5",
-                "@babel/plugin-transform-template-literals": "^7.22.5",
-                "@babel/plugin-transform-typeof-symbol": "^7.22.5",
-                "@babel/plugin-transform-unicode-escapes": "^7.22.10",
-                "@babel/plugin-transform-unicode-property-regex": "^7.22.5",
-                "@babel/plugin-transform-unicode-regex": "^7.22.5",
-                "@babel/plugin-transform-unicode-sets-regex": "^7.22.5",
+                "@babel/plugin-transform-arrow-functions": "^7.27.1",
+                "@babel/plugin-transform-async-generator-functions": "^7.27.1",
+                "@babel/plugin-transform-async-to-generator": "^7.27.1",
+                "@babel/plugin-transform-block-scoped-functions": "^7.27.1",
+                "@babel/plugin-transform-block-scoping": "^7.27.1",
+                "@babel/plugin-transform-class-properties": "^7.27.1",
+                "@babel/plugin-transform-class-static-block": "^7.27.1",
+                "@babel/plugin-transform-classes": "^7.27.1",
+                "@babel/plugin-transform-computed-properties": "^7.27.1",
+                "@babel/plugin-transform-destructuring": "^7.27.1",
+                "@babel/plugin-transform-dotall-regex": "^7.27.1",
+                "@babel/plugin-transform-duplicate-keys": "^7.27.1",
+                "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1",
+                "@babel/plugin-transform-dynamic-import": "^7.27.1",
+                "@babel/plugin-transform-exponentiation-operator": "^7.27.1",
+                "@babel/plugin-transform-export-namespace-from": "^7.27.1",
+                "@babel/plugin-transform-for-of": "^7.27.1",
+                "@babel/plugin-transform-function-name": "^7.27.1",
+                "@babel/plugin-transform-json-strings": "^7.27.1",
+                "@babel/plugin-transform-literals": "^7.27.1",
+                "@babel/plugin-transform-logical-assignment-operators": "^7.27.1",
+                "@babel/plugin-transform-member-expression-literals": "^7.27.1",
+                "@babel/plugin-transform-modules-amd": "^7.27.1",
+                "@babel/plugin-transform-modules-commonjs": "^7.27.1",
+                "@babel/plugin-transform-modules-systemjs": "^7.27.1",
+                "@babel/plugin-transform-modules-umd": "^7.27.1",
+                "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1",
+                "@babel/plugin-transform-new-target": "^7.27.1",
+                "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1",
+                "@babel/plugin-transform-numeric-separator": "^7.27.1",
+                "@babel/plugin-transform-object-rest-spread": "^7.27.2",
+                "@babel/plugin-transform-object-super": "^7.27.1",
+                "@babel/plugin-transform-optional-catch-binding": "^7.27.1",
+                "@babel/plugin-transform-optional-chaining": "^7.27.1",
+                "@babel/plugin-transform-parameters": "^7.27.1",
+                "@babel/plugin-transform-private-methods": "^7.27.1",
+                "@babel/plugin-transform-private-property-in-object": "^7.27.1",
+                "@babel/plugin-transform-property-literals": "^7.27.1",
+                "@babel/plugin-transform-regenerator": "^7.27.1",
+                "@babel/plugin-transform-regexp-modifiers": "^7.27.1",
+                "@babel/plugin-transform-reserved-words": "^7.27.1",
+                "@babel/plugin-transform-shorthand-properties": "^7.27.1",
+                "@babel/plugin-transform-spread": "^7.27.1",
+                "@babel/plugin-transform-sticky-regex": "^7.27.1",
+                "@babel/plugin-transform-template-literals": "^7.27.1",
+                "@babel/plugin-transform-typeof-symbol": "^7.27.1",
+                "@babel/plugin-transform-unicode-escapes": "^7.27.1",
+                "@babel/plugin-transform-unicode-property-regex": "^7.27.1",
+                "@babel/plugin-transform-unicode-regex": "^7.27.1",
+                "@babel/plugin-transform-unicode-sets-regex": "^7.27.1",
                 "@babel/preset-modules": "0.1.6-no-external-plugins",
                 "@babel/preset-modules": "0.1.6-no-external-plugins",
-                "@babel/types": "^7.22.15",
-                "babel-plugin-polyfill-corejs2": "^0.4.5",
-                "babel-plugin-polyfill-corejs3": "^0.8.3",
-                "babel-plugin-polyfill-regenerator": "^0.5.2",
-                "core-js-compat": "^3.31.0",
+                "babel-plugin-polyfill-corejs2": "^0.4.10",
+                "babel-plugin-polyfill-corejs3": "^0.11.0",
+                "babel-plugin-polyfill-regenerator": "^0.6.1",
+                "core-js-compat": "^3.40.0",
                 "semver": "^6.3.1"
             },
             "engines": {
                 "semver": "^6.3.1"
             },
             "engines": {
             "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
             "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
             "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/helper-plugin-utils": "^7.0.0",
                 "@babel/types": "^7.4.4",
             "dependencies": {
                 "@babel/helper-plugin-utils": "^7.0.0",
                 "@babel/types": "^7.4.4",
             }
         },
         "node_modules/@babel/preset-react": {
             }
         },
         "node_modules/@babel/preset-react": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.15.tgz",
-            "integrity": "sha512-Csy1IJ2uEh/PecCBXXoZGAZBeCATTuePzCSB7dLYWS0vOEj6CNpjxIhW4duWwZodBNueH7QO14WbGn8YyeuN9w==",
+            "version": "7.27.1",
+            "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.27.1.tgz",
+            "integrity": "sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-validator-option": "^7.22.15",
-                "@babel/plugin-transform-react-display-name": "^7.22.5",
-                "@babel/plugin-transform-react-jsx": "^7.22.15",
-                "@babel/plugin-transform-react-jsx-development": "^7.22.5",
-                "@babel/plugin-transform-react-pure-annotations": "^7.22.5"
+                "@babel/helper-plugin-utils": "^7.27.1",
+                "@babel/helper-validator-option": "^7.27.1",
+                "@babel/plugin-transform-react-display-name": "^7.27.1",
+                "@babel/plugin-transform-react-jsx": "^7.27.1",
+                "@babel/plugin-transform-react-jsx-development": "^7.27.1",
+                "@babel/plugin-transform-react-pure-annotations": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             },
             "engines": {
                 "node": ">=6.9.0"
                 "@babel/core": "^7.0.0-0"
             }
         },
                 "@babel/core": "^7.0.0-0"
             }
         },
-        "node_modules/@babel/regjsgen": {
-            "version": "0.8.0",
-            "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz",
-            "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==",
-            "dev": true
-        },
         "node_modules/@babel/runtime": {
         "node_modules/@babel/runtime": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz",
-            "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==",
-            "dependencies": {
-                "regenerator-runtime": "^0.14.0"
-            },
+            "version": "7.27.6",
+            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz",
+            "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==",
+            "license": "MIT",
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/template": {
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/template": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
-            "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==",
+            "version": "7.27.2",
+            "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+            "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/code-frame": "^7.23.5",
-                "@babel/parser": "^7.23.9",
-                "@babel/types": "^7.23.9"
+                "@babel/code-frame": "^7.27.1",
+                "@babel/parser": "^7.27.2",
+                "@babel/types": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/traverse": {
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@babel/traverse": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
-            "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/code-frame": "^7.23.5",
-                "@babel/generator": "^7.23.6",
-                "@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.9",
-                "@babel/types": "^7.23.9",
+            "version": "7.27.4",
+            "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.4.tgz",
+            "integrity": "sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/code-frame": "^7.27.1",
+                "@babel/generator": "^7.27.3",
+                "@babel/parser": "^7.27.4",
+                "@babel/template": "^7.27.2",
+                "@babel/types": "^7.27.3",
                 "debug": "^4.3.1",
                 "globals": "^11.1.0"
             },
                 "debug": "^4.3.1",
                 "globals": "^11.1.0"
             },
                 "node": ">=6.9.0"
             }
         },
                 "node": ">=6.9.0"
             }
         },
+        "node_modules/@babel/traverse/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==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
+        },
         "node_modules/@babel/types": {
         "node_modules/@babel/types": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
-            "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
+            "version": "7.27.6",
+            "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz",
+            "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-string-parser": "^7.23.4",
-                "@babel/helper-validator-identifier": "^7.22.20",
-                "to-fast-properties": "^2.0.0"
+                "@babel/helper-string-parser": "^7.27.1",
+                "@babel/helper-validator-identifier": "^7.27.1"
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@bcoe/v8-coverage": {
             },
             "engines": {
                 "node": ">=6.9.0"
             }
         },
         "node_modules/@bcoe/v8-coverage": {
-            "version": "0.2.3",
-            "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
-            "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
-            "dev": true
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz",
+            "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=18"
+            }
         },
         "node_modules/@codemirror/autocomplete": {
         },
         "node_modules/@codemirror/autocomplete": {
-            "version": "6.9.0",
-            "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.9.0.tgz",
-            "integrity": "sha512-Fbwm0V/Wn3BkEJZRhr0hi5BhCo5a7eBL6LYaliPjOSwCyfOpnjXY59HruSxOUNV+1OYer0Tgx1zRNQttjXyDog==",
+            "version": "6.18.6",
+            "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
+            "integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/language": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
             "dependencies": {
                 "@codemirror/language": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.6.0",
-                "@lezer/common": "^1.0.0"
-            },
-            "peerDependencies": {
-                "@codemirror/language": "^6.0.0",
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0",
+                "@codemirror/view": "^6.17.0",
                 "@lezer/common": "^1.0.0"
             }
         },
         "node_modules/@codemirror/commands": {
                 "@lezer/common": "^1.0.0"
             }
         },
         "node_modules/@codemirror/commands": {
-            "version": "6.2.5",
-            "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.5.tgz",
-            "integrity": "sha512-dSi7ow2P2YgPBZflR9AJoaTHvqmeGIgkhignYMd5zK5y6DANTvxKxp6eMEpIDUJkRAaOY/TFZ4jP1ADIO/GLVA==",
+            "version": "6.8.1",
+            "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
+            "integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/language": "^6.0.0",
             "dependencies": {
                 "@codemirror/language": "^6.0.0",
-                "@codemirror/state": "^6.2.0",
-                "@codemirror/view": "^6.0.0",
-                "@lezer/common": "^1.0.0"
+                "@codemirror/state": "^6.4.0",
+                "@codemirror/view": "^6.27.0",
+                "@lezer/common": "^1.1.0"
             }
         },
         "node_modules/@codemirror/lang-css": {
             }
         },
         "node_modules/@codemirror/lang-css": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.2.1.tgz",
-            "integrity": "sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==",
+            "version": "6.3.1",
+            "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz",
+            "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/language": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
                 "@lezer/common": "^1.0.2",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/language": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
                 "@lezer/common": "^1.0.2",
-                "@lezer/css": "^1.0.0"
+                "@lezer/css": "^1.1.7"
             }
         },
         "node_modules/@codemirror/lang-html": {
             }
         },
         "node_modules/@codemirror/lang-html": {
-            "version": "6.4.6",
-            "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.6.tgz",
-            "integrity": "sha512-E4C8CVupBksXvgLSme/zv31x91g06eZHSph7NczVxZW+/K+3XgJGWNT//2WLzaKSBoxpAjaOi5ZnPU1SHhjh3A==",
+            "version": "6.4.9",
+            "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.9.tgz",
+            "integrity": "sha512-aQv37pIMSlueybId/2PVSP6NPnmurFDVmZwzc7jszd2KAF8qd4VBbvNYPXWQq90WIARjsdVkPbw29pszmHws3Q==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/lang-css": "^6.0.0",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/lang-css": "^6.0.0",
             }
         },
         "node_modules/@codemirror/lang-javascript": {
             }
         },
         "node_modules/@codemirror/lang-javascript": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.1.tgz",
-            "integrity": "sha512-jlFOXTejVyiQCW3EQwvKH0m99bUYIw40oPmFjSX2VS78yzfe0HELZ+NEo9Yfo1MkGRpGlj3Gnu4rdxV1EnAs5A==",
+            "version": "6.2.4",
+            "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
+            "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/language": "^6.6.0",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/language": "^6.6.0",
             }
         },
         "node_modules/@codemirror/language": {
             }
         },
         "node_modules/@codemirror/language": {
-            "version": "6.9.0",
-            "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.9.0.tgz",
-            "integrity": "sha512-nFu311/0ne/qGuGCL3oKuktBgzVOaxCHZPZv1tLSZkNjPYxxvkjSbzno3MlErG2tgw1Yw1yF8BxMCegeMXqpiw==",
+            "version": "6.11.1",
+            "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz",
+            "integrity": "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/state": "^6.0.0",
             "dependencies": {
                 "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0",
-                "@lezer/common": "^1.0.0",
+                "@codemirror/view": "^6.23.0",
+                "@lezer/common": "^1.1.0",
                 "@lezer/highlight": "^1.0.0",
                 "@lezer/lr": "^1.0.0",
                 "style-mod": "^4.0.0"
             }
         },
         "node_modules/@codemirror/lint": {
                 "@lezer/highlight": "^1.0.0",
                 "@lezer/lr": "^1.0.0",
                 "style-mod": "^4.0.0"
             }
         },
         "node_modules/@codemirror/lint": {
-            "version": "6.4.1",
-            "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.4.1.tgz",
-            "integrity": "sha512-2Hx945qKX7FBan5/gUdTM8fsMYrNG9clIgEcPXestbLVFAUyQYFAuju/5BMNf/PwgpVaX5pvRm4+ovjbp9D9gQ==",
+            "version": "6.8.5",
+            "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
+            "integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/state": "^6.0.0",
             "dependencies": {
                 "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0",
+                "@codemirror/view": "^6.35.0",
                 "crelt": "^1.0.5"
             }
         },
         "node_modules/@codemirror/search": {
                 "crelt": "^1.0.5"
             }
         },
         "node_modules/@codemirror/search": {
-            "version": "6.5.2",
-            "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.2.tgz",
-            "integrity": "sha512-WRihpqd0l9cEh9J3IZe45Yi+Z5MfTsEXnyc3V7qXHP4ZYtIYpGOn+EJ7fyLIkyAm/8S6QIr7/mMISfAadf8zCg==",
+            "version": "6.5.11",
+            "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
+            "integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/state": "^6.0.0",
                 "@codemirror/view": "^6.0.0",
             "dependencies": {
                 "@codemirror/state": "^6.0.0",
                 "@codemirror/view": "^6.0.0",
             }
         },
         "node_modules/@codemirror/state": {
             }
         },
         "node_modules/@codemirror/state": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.1.tgz",
-            "integrity": "sha512-RupHSZ8+OjNT38zU9fKH2sv+Dnlr8Eb8sl4NOnnqz95mCFTZUaiRP8Xv5MeeaG0px2b8Bnfe7YGwCV3nsBhbuw=="
+            "version": "6.5.2",
+            "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
+            "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
+            "license": "MIT",
+            "dependencies": {
+                "@marijn/find-cluster-break": "^1.0.0"
+            }
         },
         "node_modules/@codemirror/theme-one-dark": {
         },
         "node_modules/@codemirror/theme-one-dark": {
-            "version": "6.1.2",
-            "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
-            "integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
+            "version": "6.1.3",
+            "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
+            "integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/language": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
             "dependencies": {
                 "@codemirror/language": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
             }
         },
         "node_modules/@codemirror/view": {
             }
         },
         "node_modules/@codemirror/view": {
-            "version": "6.18.0",
-            "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.18.0.tgz",
-            "integrity": "sha512-T6q1yYAoU+gSWfJFR4ryvDQcyOqS+Mw5RCvh26y0KiNksOOLYhNvdB3BTyLz8vy4fKaYlzbAOyBU7OQPUGHzjQ==",
+            "version": "6.37.2",
+            "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.2.tgz",
+            "integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@codemirror/state": "^6.1.4",
+                "@codemirror/state": "^6.5.0",
+                "crelt": "^1.0.6",
                 "style-mod": "^4.1.0",
                 "w3c-keyname": "^2.2.4"
             }
                 "style-mod": "^4.1.0",
                 "w3c-keyname": "^2.2.4"
             }
             "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
             "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
             "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
             "dev": true,
+            "license": "MIT",
             "optional": true,
             "engines": {
                 "node": ">=0.1.90"
             }
         },
             "optional": true,
             "engines": {
                 "node": ">=0.1.90"
             }
         },
-        "node_modules/@discoveryjs/json-ext": {
-            "version": "0.5.7",
-            "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
-            "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
+        "node_modules/@csstools/color-helpers": {
+            "version": "5.0.2",
+            "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz",
+            "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==",
             "dev": true,
             "dev": true,
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/csstools"
+                },
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/csstools"
+                }
+            ],
+            "license": "MIT-0",
             "engines": {
             "engines": {
-                "node": ">=10.0.0"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@eslint-community/eslint-utils": {
-            "version": "4.4.0",
-            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
-            "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+        "node_modules/@csstools/css-calc": {
+            "version": "2.1.4",
+            "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz",
+            "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "eslint-visitor-keys": "^3.3.0"
-            },
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/csstools"
+                },
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/csstools"
+                }
+            ],
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+                "node": ">=18"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+                "@csstools/css-parser-algorithms": "^3.0.5",
+                "@csstools/css-tokenizer": "^3.0.4"
             }
         },
             }
         },
-        "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
-            "version": "3.4.3",
-            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-            "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+        "node_modules/@csstools/css-color-parser": {
+            "version": "3.0.10",
+            "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz",
+            "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==",
             "dev": true,
             "dev": true,
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/csstools"
+                },
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/csstools"
+                }
+            ],
+            "license": "MIT",
+            "dependencies": {
+                "@csstools/color-helpers": "^5.0.2",
+                "@csstools/css-calc": "^2.1.4"
+            },
             "engines": {
             "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+                "node": ">=18"
             },
             },
-            "funding": {
-                "url": "https://opencollective.com/eslint"
+            "peerDependencies": {
+                "@csstools/css-parser-algorithms": "^3.0.5",
+                "@csstools/css-tokenizer": "^3.0.4"
             }
         },
             }
         },
-        "node_modules/@eslint-community/regexpp": {
-            "version": "4.8.0",
-            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz",
-            "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==",
+        "node_modules/@csstools/css-parser-algorithms": {
+            "version": "3.0.5",
+            "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz",
+            "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==",
             "dev": true,
             "dev": true,
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/csstools"
+                },
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/csstools"
+                }
+            ],
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+                "node": ">=18"
+            },
+            "peerDependencies": {
+                "@csstools/css-tokenizer": "^3.0.4"
             }
         },
             }
         },
-        "node_modules/@eslint/eslintrc": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
-            "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
+        "node_modules/@csstools/css-tokenizer": {
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz",
+            "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ajv": "^6.12.4",
-                "debug": "^4.3.2",
-                "espree": "^9.6.0",
-                "globals": "^13.19.0",
-                "ignore": "^5.2.0",
-                "import-fresh": "^3.2.1",
-                "js-yaml": "^4.1.0",
-                "minimatch": "^3.1.2",
-                "strip-json-comments": "^3.1.1"
-            },
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/csstools"
+                },
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/csstools"
+                }
+            ],
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-            },
-            "funding": {
-                "url": "https://opencollective.com/eslint"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@eslint/eslintrc/node_modules/globals": {
-            "version": "13.21.0",
-            "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
-            "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
+        "node_modules/@discoveryjs/json-ext": {
+            "version": "0.5.7",
+            "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
+            "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "type-fest": "^0.20.2"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+                "node": ">=10.0.0"
             }
         },
             }
         },
-        "node_modules/@eslint/js": {
-            "version": "8.48.0",
-            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz",
-            "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==",
+        "node_modules/@esbuild/aix-ppc64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
+            "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
+            "cpu": [
+                "ppc64"
+            ],
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "aix"
+            ],
             "engines": {
             "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@fortawesome/fontawesome-common-types": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz",
-            "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==",
-            "hasInstallScript": true,
+        "node_modules/@esbuild/android-arm": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
+            "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
             "engines": {
             "engines": {
-                "node": ">=6"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@fortawesome/fontawesome-free": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.2.tgz",
-            "integrity": "sha512-m5cPn3e2+FDCOgi1mz0RexTUvvQibBebOUlUlW0+YrMjDTPkiJ6VTKukA1GRsvRw+12KyJndNjj0O4AgTxm2Pg==",
-            "hasInstallScript": true,
+        "node_modules/@esbuild/android-arm64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
+            "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
             "engines": {
             "engines": {
-                "node": ">=6"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@fortawesome/fontawesome-svg-core": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz",
-            "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==",
-            "hasInstallScript": true,
-            "dependencies": {
-                "@fortawesome/fontawesome-common-types": "6.4.2"
-            },
+        "node_modules/@esbuild/android-x64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
+            "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
             "engines": {
             "engines": {
-                "node": ">=6"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@fortawesome/free-brands-svg-icons": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz",
-            "integrity": "sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==",
-            "hasInstallScript": true,
-            "dependencies": {
-                "@fortawesome/fontawesome-common-types": "6.4.2"
-            },
+        "node_modules/@esbuild/darwin-arm64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
+            "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
             "engines": {
             "engines": {
-                "node": ">=6"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@fortawesome/free-solid-svg-icons": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.2.tgz",
-            "integrity": "sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==",
-            "hasInstallScript": true,
-            "dependencies": {
-                "@fortawesome/fontawesome-common-types": "6.4.2"
-            },
+        "node_modules/@esbuild/darwin-x64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
+            "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
             "engines": {
             "engines": {
-                "node": ">=6"
-            }
-        },
-        "node_modules/@fortawesome/react-fontawesome": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
-            "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
-            "dependencies": {
-                "prop-types": "^15.8.1"
-            },
-            "peerDependencies": {
-                "@fortawesome/fontawesome-svg-core": "~1 || ~6",
-                "react": ">=16.3"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@humanwhocodes/config-array": {
-            "version": "0.11.11",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
-            "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
+        "node_modules/@esbuild/freebsd-arm64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
+            "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
+            "cpu": [
+                "arm64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@humanwhocodes/object-schema": "^1.2.1",
-                "debug": "^4.1.1",
-                "minimatch": "^3.0.5"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
             "engines": {
             "engines": {
-                "node": ">=10.10.0"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@humanwhocodes/module-importer": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-            "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+        "node_modules/@esbuild/freebsd-x64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
+            "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
+            "cpu": [
+                "x64"
+            ],
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
             "engines": {
             "engines": {
-                "node": ">=12.22"
-            },
-            "funding": {
-                "type": "github",
-                "url": "https://github.com/sponsors/nzakas"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@humanwhocodes/object-schema": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
-            "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
-            "dev": true
+        "node_modules/@esbuild/linux-arm": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
+            "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=18"
+            }
         },
         },
-        "node_modules/@istanbuljs/load-nyc-config": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
-            "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+        "node_modules/@esbuild/linux-arm64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
+            "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
+            "cpu": [
+                "arm64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "camelcase": "^5.3.1",
-                "find-up": "^4.1.0",
-                "get-package-type": "^0.1.0",
-                "js-yaml": "^3.13.1",
-                "resolve-from": "^5.0.0"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
-            "version": "1.0.10",
-            "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-            "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+        "node_modules/@esbuild/linux-ia32": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
+            "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
+            "cpu": [
+                "ia32"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "sprintf-js": "~1.0.2"
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-            "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+        "node_modules/@esbuild/linux-loong64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
+            "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
+            "cpu": [
+                "loong64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "locate-path": "^5.0.0",
-                "path-exists": "^4.0.0"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
-            "version": "3.14.1",
-            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-            "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+        "node_modules/@esbuild/linux-mips64el": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
+            "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
+            "cpu": [
+                "mips64el"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "argparse": "^1.0.7",
-                "esprima": "^4.0.0"
-            },
-            "bin": {
-                "js-yaml": "bin/js-yaml.js"
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-            "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+        "node_modules/@esbuild/linux-ppc64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
+            "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
+            "cpu": [
+                "ppc64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "p-locate": "^4.1.0"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-            "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+        "node_modules/@esbuild/linux-riscv64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
+            "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
+            "cpu": [
+                "riscv64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "p-try": "^2.0.0"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
             "engines": {
             "engines": {
-                "node": ">=6"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-            "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+        "node_modules/@esbuild/linux-s390x": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
+            "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
+            "cpu": [
+                "s390x"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "p-limit": "^2.2.0"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
-            "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+        "node_modules/@esbuild/linux-x64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
+            "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
+            "cpu": [
+                "x64"
+            ],
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@istanbuljs/schema": {
-            "version": "0.1.3",
-            "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
-            "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+        "node_modules/@esbuild/netbsd-arm64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
+            "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
+            "cpu": [
+                "arm64"
+            ],
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "netbsd"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@jest/console": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz",
-            "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
+        "node_modules/@esbuild/netbsd-x64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
+            "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
+            "cpu": [
+                "x64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "jest-message-util": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "slash": "^3.0.0"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "netbsd"
+            ],
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@jest/console/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/@esbuild/openbsd-arm64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
+            "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
+            "cpu": [
+                "arm64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "openbsd"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@jest/console/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/@esbuild/openbsd-x64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
+            "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
+            "cpu": [
+                "x64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "openbsd"
+            ],
             "engines": {
             "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@jest/console/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/@esbuild/sunos-x64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
+            "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
+            "cpu": [
+                "x64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "sunos"
+            ],
             "engines": {
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@jest/console/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
+        "node_modules/@esbuild/win32-arm64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
+            "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">=18"
+            }
         },
         },
-        "node_modules/@jest/console/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/@esbuild/win32-ia32": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
+            "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
+            "cpu": [
+                "ia32"
+            ],
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@jest/console/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/@esbuild/win32-x64": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
+            "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
+            "cpu": [
+                "x64"
+            ],
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/@jest/core": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz",
-            "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
+        "node_modules/@eslint-community/eslint-utils": {
+            "version": "4.7.0",
+            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
+            "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/console": "^29.7.0",
-                "@jest/reporters": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "ansi-escapes": "^4.2.1",
-                "chalk": "^4.0.0",
-                "ci-info": "^3.2.0",
-                "exit": "^0.1.2",
-                "graceful-fs": "^4.2.9",
-                "jest-changed-files": "^29.7.0",
-                "jest-config": "^29.7.0",
-                "jest-haste-map": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-regex-util": "^29.6.3",
-                "jest-resolve": "^29.7.0",
-                "jest-resolve-dependencies": "^29.7.0",
-                "jest-runner": "^29.7.0",
-                "jest-runtime": "^29.7.0",
-                "jest-snapshot": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-validate": "^29.7.0",
-                "jest-watcher": "^29.7.0",
-                "micromatch": "^4.0.4",
-                "pretty-format": "^29.7.0",
-                "slash": "^3.0.0",
-                "strip-ansi": "^6.0.0"
+                "eslint-visitor-keys": "^3.4.3"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
             },
             },
-            "peerDependencies": {
-                "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+            "funding": {
+                "url": "https://opencollective.com/eslint"
             },
             },
-            "peerDependenciesMeta": {
-                "node-notifier": {
-                    "optional": true
-                }
+            "peerDependencies": {
+                "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
             }
         },
             }
         },
-        "node_modules/@jest/core/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+            "version": "3.4.3",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+            "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "url": "https://opencollective.com/eslint"
             }
         },
             }
         },
-        "node_modules/@jest/core/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/@eslint-community/regexpp": {
+            "version": "4.12.1",
+            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
+            "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
             }
         },
             }
         },
-        "node_modules/@jest/core/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/@eslint/config-array": {
+            "version": "0.20.1",
+            "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.1.tgz",
+            "integrity": "sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "@eslint/object-schema": "^2.1.6",
+                "debug": "^4.3.1",
+                "minimatch": "^3.1.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             }
         },
             }
         },
-        "node_modules/@jest/core/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/@jest/core/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/@eslint/config-helpers": {
+            "version": "0.2.3",
+            "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.3.tgz",
+            "integrity": "sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             }
         },
             }
         },
-        "node_modules/@jest/core/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/@eslint/core": {
+            "version": "0.14.0",
+            "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
+            "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "@types/json-schema": "^7.0.15"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             }
         },
             }
         },
-        "node_modules/@jest/environment": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
-            "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
+        "node_modules/@eslint/eslintrc": {
+            "version": "3.3.1",
+            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
+            "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/fake-timers": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "jest-mock": "^29.7.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
-        "node_modules/@jest/expect": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz",
-            "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
-            "dev": true,
-            "dependencies": {
-                "expect": "^29.7.0",
-                "jest-snapshot": "^29.7.0"
+                "ajv": "^6.12.4",
+                "debug": "^4.3.2",
+                "espree": "^10.0.1",
+                "globals": "^14.0.0",
+                "ignore": "^5.2.0",
+                "import-fresh": "^3.2.1",
+                "js-yaml": "^4.1.0",
+                "minimatch": "^3.1.2",
+                "strip-json-comments": "^3.1.1"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
-        "node_modules/@jest/expect-utils": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
-            "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
-            "dev": true,
-            "dependencies": {
-                "jest-get-type": "^29.6.3"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
             },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+            "funding": {
+                "url": "https://opencollective.com/eslint"
             }
         },
             }
         },
-        "node_modules/@jest/fake-timers": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
-            "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
+        "node_modules/@eslint/eslintrc/node_modules/globals": {
+            "version": "14.0.0",
+            "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+            "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@jest/types": "^29.6.3",
-                "@sinonjs/fake-timers": "^10.0.2",
-                "@types/node": "*",
-                "jest-message-util": "^29.7.0",
-                "jest-mock": "^29.7.0",
-                "jest-util": "^29.7.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
-        "node_modules/@jest/globals": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
-            "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
-            "dev": true,
-            "dependencies": {
-                "@jest/environment": "^29.7.0",
-                "@jest/expect": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "jest-mock": "^29.7.0"
+                "node": ">=18"
             },
             },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/@jest/reporters": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz",
-            "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
+        "node_modules/@eslint/js": {
+            "version": "9.29.0",
+            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.29.0.tgz",
+            "integrity": "sha512-3PIF4cBw/y+1u2EazflInpV+lYsSG0aByVIQzAgb1m1MhHFSbqTyNqtBKHgWf/9Ykud+DhILS9EGkmekVhbKoQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@bcoe/v8-coverage": "^0.2.3",
-                "@jest/console": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@jridgewell/trace-mapping": "^0.3.18",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "collect-v8-coverage": "^1.0.0",
-                "exit": "^0.1.2",
-                "glob": "^7.1.3",
-                "graceful-fs": "^4.2.9",
-                "istanbul-lib-coverage": "^3.0.0",
-                "istanbul-lib-instrument": "^6.0.0",
-                "istanbul-lib-report": "^3.0.0",
-                "istanbul-lib-source-maps": "^4.0.0",
-                "istanbul-reports": "^3.1.3",
-                "jest-message-util": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-worker": "^29.7.0",
-                "slash": "^3.0.0",
-                "string-length": "^4.0.1",
-                "strip-ansi": "^6.0.0",
-                "v8-to-istanbul": "^9.0.1"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            },
-            "peerDependencies": {
-                "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
             },
-            "peerDependenciesMeta": {
-                "node-notifier": {
-                    "optional": true
-                }
+            "funding": {
+                "url": "https://eslint.org/donate"
             }
         },
             }
         },
-        "node_modules/@jest/reporters/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/@eslint/object-schema": {
+            "version": "2.1.6",
+            "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz",
+            "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             }
         },
             }
         },
-        "node_modules/@jest/reporters/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/@eslint/plugin-kit": {
+            "version": "0.3.2",
+            "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz",
+            "integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
+                "@eslint/core": "^0.15.0",
+                "levn": "^0.4.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             }
         },
             }
         },
-        "node_modules/@jest/reporters/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
+            "version": "0.15.0",
+            "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz",
+            "integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "@types/json-schema": "^7.0.15"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             }
         },
             }
         },
-        "node_modules/@jest/reporters/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/@jest/reporters/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
+        "node_modules/@fortawesome/fontawesome-common-types": {
+            "version": "6.7.2",
+            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
+            "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/@jest/reporters/node_modules/jest-worker": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
-            "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
-            "dev": true,
-            "dependencies": {
-                "@types/node": "*",
-                "jest-util": "^29.7.0",
-                "merge-stream": "^2.0.0",
-                "supports-color": "^8.0.0"
-            },
+        "node_modules/@fortawesome/fontawesome-free": {
+            "version": "6.7.2",
+            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz",
+            "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==",
+            "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/@jest/reporters/node_modules/jest-worker/node_modules/supports-color": {
-            "version": "8.1.1",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-            "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
-            "dev": true,
+        "node_modules/@fortawesome/fontawesome-svg-core": {
+            "version": "6.7.2",
+            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
+            "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "@fortawesome/fontawesome-common-types": "6.7.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/supports-color?sponsor=1"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/@jest/reporters/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-            "dev": true,
+        "node_modules/@fortawesome/free-brands-svg-icons": {
+            "version": "6.7.2",
+            "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz",
+            "integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==",
+            "license": "(CC-BY-4.0 AND MIT)",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "@fortawesome/fontawesome-common-types": "6.7.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/@jest/schemas": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
-            "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
-            "dev": true,
+        "node_modules/@fortawesome/free-solid-svg-icons": {
+            "version": "6.7.2",
+            "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz",
+            "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==",
+            "license": "(CC-BY-4.0 AND MIT)",
             "dependencies": {
             "dependencies": {
-                "@sinclair/typebox": "^0.27.8"
+                "@fortawesome/fontawesome-common-types": "6.7.2"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/@jest/source-map": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
-            "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
-            "dev": true,
+        "node_modules/@fortawesome/react-fontawesome": {
+            "version": "0.2.2",
+            "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz",
+            "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jridgewell/trace-mapping": "^0.3.18",
-                "callsites": "^3.0.0",
-                "graceful-fs": "^4.2.9"
+                "prop-types": "^15.8.1"
             },
             },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+            "peerDependencies": {
+                "@fortawesome/fontawesome-svg-core": "~1 || ~6",
+                "react": ">=16.3"
             }
         },
             }
         },
-        "node_modules/@jest/test-result": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz",
-            "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
+        "node_modules/@humanfs/core": {
+            "version": "0.19.1",
+            "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz",
+            "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@jest/console": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/istanbul-lib-coverage": "^2.0.0",
-                "collect-v8-coverage": "^1.0.0"
-            },
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=18.18.0"
             }
         },
             }
         },
-        "node_modules/@jest/test-sequencer": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
-            "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
+        "node_modules/@humanfs/node": {
+            "version": "0.16.6",
+            "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+            "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
-                "@jest/test-result": "^29.7.0",
-                "graceful-fs": "^4.2.9",
-                "jest-haste-map": "^29.7.0",
-                "slash": "^3.0.0"
+                "@humanfs/core": "^0.19.1",
+                "@humanwhocodes/retry": "^0.3.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=18.18.0"
             }
         },
             }
         },
-        "node_modules/@jest/transform": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
-            "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
+        "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": {
+            "version": "0.3.1",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz",
+            "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@babel/core": "^7.11.6",
-                "@jest/types": "^29.6.3",
-                "@jridgewell/trace-mapping": "^0.3.18",
-                "babel-plugin-istanbul": "^6.1.1",
-                "chalk": "^4.0.0",
-                "convert-source-map": "^2.0.0",
-                "fast-json-stable-stringify": "^2.1.0",
-                "graceful-fs": "^4.2.9",
-                "jest-haste-map": "^29.7.0",
-                "jest-regex-util": "^29.6.3",
-                "jest-util": "^29.7.0",
-                "micromatch": "^4.0.4",
-                "pirates": "^4.0.4",
-                "slash": "^3.0.0",
-                "write-file-atomic": "^4.0.2"
-            },
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=18.18"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/nzakas"
             }
         },
             }
         },
-        "node_modules/@jest/transform/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/@humanwhocodes/module-importer": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+            "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=12.22"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "type": "github",
+                "url": "https://github.com/sponsors/nzakas"
             }
         },
             }
         },
-        "node_modules/@jest/transform/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/@humanwhocodes/retry": {
+            "version": "0.4.3",
+            "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+            "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": ">=10"
+                "node": ">=18.18"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "type": "github",
+                "url": "https://github.com/sponsors/nzakas"
             }
         },
             }
         },
-        "node_modules/@jest/transform/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/@isaacs/cliui": {
+            "version": "8.0.2",
+            "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+            "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "string-width": "^5.1.2",
+                "string-width-cjs": "npm:string-width@^4.2.0",
+                "strip-ansi": "^7.0.1",
+                "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+                "wrap-ansi": "^8.1.0",
+                "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">=12"
             }
         },
             }
         },
-        "node_modules/@jest/transform/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/@jest/transform/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==",
-            "dev": true
-        },
-        "node_modules/@jest/transform/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+            "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-regex?sponsor=1"
             }
         },
             }
         },
-        "node_modules/@jest/transform/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
+            "version": "6.2.1",
+            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
+            "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
             }
         },
             }
         },
-        "node_modules/@jest/types": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
-            "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+        "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
+            "version": "9.2.2",
+            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+            "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@jest/schemas": "^29.6.3",
-                "@types/istanbul-lib-coverage": "^2.0.0",
-                "@types/istanbul-reports": "^3.0.0",
-                "@types/node": "*",
-                "@types/yargs": "^17.0.8",
-                "chalk": "^4.0.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/@jest/types/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/@isaacs/cliui/node_modules/string-width": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+            "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^2.0.1"
+                "eastasianwidth": "^0.2.0",
+                "emoji-regex": "^9.2.2",
+                "strip-ansi": "^7.0.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=12"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/@jest/types/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+            "version": "7.1.0",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+            "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
+                "ansi-regex": "^6.0.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": ">=12"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "url": "https://github.com/chalk/strip-ansi?sponsor=1"
             }
         },
             }
         },
-        "node_modules/@jest/types/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
+            "version": "8.1.0",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+            "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "ansi-styles": "^6.1.0",
+                "string-width": "^5.0.1",
+                "strip-ansi": "^7.0.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/@jest/types/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/@jest/types/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
             }
         },
             }
         },
-        "node_modules/@jest/types/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/@istanbuljs/schema": {
+            "version": "0.1.3",
+            "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+            "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             }
         },
         "node_modules/@jridgewell/gen-mapping": {
             "engines": {
                 "node": ">=8"
             }
         },
         "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==",
+            "version": "0.3.8",
+            "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+            "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jridgewell/set-array": "^1.0.1",
+                "@jridgewell/set-array": "^1.2.1",
                 "@jridgewell/sourcemap-codec": "^1.4.10",
                 "@jridgewell/sourcemap-codec": "^1.4.10",
-                "@jridgewell/trace-mapping": "^0.3.9"
+                "@jridgewell/trace-mapping": "^0.3.24"
             },
             "engines": {
                 "node": ">=6.0.0"
             }
         },
         "node_modules/@jridgewell/resolve-uri": {
             },
             "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==",
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+            "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.0.0"
             }
         },
         "node_modules/@jridgewell/set-array": {
             "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==",
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+            "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.0.0"
             }
         },
         "node_modules/@jridgewell/source-map": {
             "engines": {
                 "node": ">=6.0.0"
             }
         },
         "node_modules/@jridgewell/source-map": {
-            "version": "0.3.5",
-            "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
-            "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
+            "version": "0.3.6",
+            "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
+            "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jridgewell/gen-mapping": "^0.3.0",
-                "@jridgewell/trace-mapping": "^0.3.9"
+                "@jridgewell/gen-mapping": "^0.3.5",
+                "@jridgewell/trace-mapping": "^0.3.25"
             }
         },
         "node_modules/@jridgewell/sourcemap-codec": {
             }
         },
         "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==",
-            "dev": true
+            "version": "1.5.0",
+            "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+            "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@jridgewell/trace-mapping": {
         },
         "node_modules/@jridgewell/trace-mapping": {
-            "version": "0.3.19",
-            "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
-            "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
+            "version": "0.3.25",
+            "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+            "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@jridgewell/resolve-uri": "^3.1.0",
                 "@jridgewell/sourcemap-codec": "^1.4.14"
             }
         },
         "node_modules/@leichtgewicht/ip-codec": {
             "dependencies": {
                 "@jridgewell/resolve-uri": "^3.1.0",
                 "@jridgewell/sourcemap-codec": "^1.4.14"
             }
         },
         "node_modules/@leichtgewicht/ip-codec": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
-            "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
-            "dev": true
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
+            "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@lezer/common": {
         },
         "node_modules/@lezer/common": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.4.tgz",
-            "integrity": "sha512-lZHlk8p67x4aIDtJl6UQrXSOP6oi7dQR3W/geFVrENdA1JDaAJWldnVqVjPMJupbTKbzDfFcePfKttqVidS/dg=="
+            "version": "1.2.3",
+            "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
+            "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
+            "license": "MIT"
         },
         "node_modules/@lezer/css": {
         },
         "node_modules/@lezer/css": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.3.tgz",
-            "integrity": "sha512-SjSM4pkQnQdJDVc80LYzEaMiNy9txsFbI7HsMgeVF28NdLaAdHNtQ+kB/QqDUzRBV/75NTXjJ/R5IdC8QQGxMg==",
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.2.1.tgz",
+            "integrity": "sha512-2F5tOqzKEKbCUNraIXc0f6HKeyKlmMWJnBB0i4XW6dJgssrZO/YlZ2pY5xgyqDleqqhiNJ3dQhbrV2aClZQMvg==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
+                "@lezer/common": "^1.2.0",
                 "@lezer/highlight": "^1.0.0",
                 "@lezer/highlight": "^1.0.0",
-                "@lezer/lr": "^1.0.0"
+                "@lezer/lr": "^1.3.0"
             }
         },
         "node_modules/@lezer/highlight": {
             }
         },
         "node_modules/@lezer/highlight": {
-            "version": "1.1.6",
-            "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.6.tgz",
-            "integrity": "sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==",
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
+            "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
+            "license": "MIT",
             "dependencies": {
                 "@lezer/common": "^1.0.0"
             }
         },
         "node_modules/@lezer/html": {
             "dependencies": {
                 "@lezer/common": "^1.0.0"
             }
         },
         "node_modules/@lezer/html": {
-            "version": "1.3.6",
-            "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.6.tgz",
-            "integrity": "sha512-Kk9HJARZTc0bAnMQUqbtuhFVsB4AnteR2BFUWfZV7L/x1H0aAKz6YabrfJ2gk/BEgjh9L3hg5O4y2IDZRBdzuQ==",
+            "version": "1.3.10",
+            "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.10.tgz",
+            "integrity": "sha512-dqpT8nISx/p9Do3AchvYGV3qYc4/rKr3IBZxlHmpIKam56P47RSHkSF5f13Vu9hebS1jM0HmtJIwLbWz1VIY6w==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@lezer/common": "^1.0.0",
+                "@lezer/common": "^1.2.0",
                 "@lezer/highlight": "^1.0.0",
                 "@lezer/lr": "^1.0.0"
             }
         },
         "node_modules/@lezer/javascript": {
                 "@lezer/highlight": "^1.0.0",
                 "@lezer/lr": "^1.0.0"
             }
         },
         "node_modules/@lezer/javascript": {
-            "version": "1.4.7",
-            "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.7.tgz",
-            "integrity": "sha512-OVWlK0YEi7HM+9JRWtRkir8qvcg0/kVYg2TAMHlVtl6DU1C9yK1waEOLBMztZsV/axRJxsqfJKhzYz+bxZme5g==",
+            "version": "1.5.1",
+            "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.1.tgz",
+            "integrity": "sha512-ATOImjeVJuvgm3JQ/bpo2Tmv55HSScE2MTPnKRMRIPx2cLhHGyX2VnqpHhtIV1tVzIjZDbcWQm+NCTF40ggZVw==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
+                "@lezer/common": "^1.2.0",
                 "@lezer/highlight": "^1.1.3",
                 "@lezer/lr": "^1.3.0"
             }
         },
         "node_modules/@lezer/lr": {
                 "@lezer/highlight": "^1.1.3",
                 "@lezer/lr": "^1.3.0"
             }
         },
         "node_modules/@lezer/lr": {
-            "version": "1.3.10",
-            "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.10.tgz",
-            "integrity": "sha512-BZfVvf7Re5BIwJHlZXbJn9L8lus5EonxQghyn+ih8Wl36XMFBPTXC0KM0IdUtj9w/diPHsKlXVgL+AlX2jYJ0Q==",
+            "version": "1.4.2",
+            "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
+            "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
+            "license": "MIT",
             "dependencies": {
                 "@lezer/common": "^1.0.0"
             }
         },
             "dependencies": {
                 "@lezer/common": "^1.0.0"
             }
         },
+        "node_modules/@marijn/find-cluster-break": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
+            "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
+            "license": "MIT"
+        },
         "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
             "version": "5.1.1-v1",
             "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
             "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
             "dev": true,
         "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
             "version": "5.1.1-v1",
             "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
             "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "eslint-scope": "5.1.1"
             }
             "dependencies": {
                 "eslint-scope": "5.1.1"
             }
             "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
             "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
             "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@nodelib/fs.stat": "2.0.5",
                 "run-parallel": "^1.1.9"
             "dependencies": {
                 "@nodelib/fs.stat": "2.0.5",
                 "run-parallel": "^1.1.9"
             "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
             "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
             "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 8"
             }
             "engines": {
                 "node": ">= 8"
             }
             "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
             "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
             "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@nodelib/fs.scandir": "2.1.5",
                 "fastq": "^1.6.0"
             "dependencies": {
                 "@nodelib/fs.scandir": "2.1.5",
                 "fastq": "^1.6.0"
                 "node": ">= 8"
             }
         },
                 "node": ">= 8"
             }
         },
+        "node_modules/@parcel/watcher": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
+            "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
+            "dev": true,
+            "hasInstallScript": true,
+            "license": "MIT",
+            "optional": true,
+            "dependencies": {
+                "detect-libc": "^1.0.3",
+                "is-glob": "^4.0.3",
+                "micromatch": "^4.0.5",
+                "node-addon-api": "^7.0.0"
+            },
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            },
+            "optionalDependencies": {
+                "@parcel/watcher-android-arm64": "2.5.1",
+                "@parcel/watcher-darwin-arm64": "2.5.1",
+                "@parcel/watcher-darwin-x64": "2.5.1",
+                "@parcel/watcher-freebsd-x64": "2.5.1",
+                "@parcel/watcher-linux-arm-glibc": "2.5.1",
+                "@parcel/watcher-linux-arm-musl": "2.5.1",
+                "@parcel/watcher-linux-arm64-glibc": "2.5.1",
+                "@parcel/watcher-linux-arm64-musl": "2.5.1",
+                "@parcel/watcher-linux-x64-glibc": "2.5.1",
+                "@parcel/watcher-linux-x64-musl": "2.5.1",
+                "@parcel/watcher-win32-arm64": "2.5.1",
+                "@parcel/watcher-win32-ia32": "2.5.1",
+                "@parcel/watcher-win32-x64": "2.5.1"
+            }
+        },
+        "node_modules/@parcel/watcher-android-arm64": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
+            "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-darwin-arm64": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
+            "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-darwin-x64": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
+            "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-freebsd-x64": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
+            "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-linux-arm-glibc": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
+            "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-linux-arm-musl": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
+            "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-linux-arm64-glibc": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
+            "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-linux-arm64-musl": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
+            "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-linux-x64-glibc": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
+            "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-linux-x64-musl": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
+            "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-win32-arm64": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
+            "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-win32-ia32": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
+            "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
+            "cpu": [
+                "ia32"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@parcel/watcher-win32-x64": {
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
+            "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ],
+            "engines": {
+                "node": ">= 10.0.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/parcel"
+            }
+        },
+        "node_modules/@pkgjs/parseargs": {
+            "version": "0.11.0",
+            "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+            "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "engines": {
+                "node": ">=14"
+            }
+        },
         "node_modules/@popperjs/core": {
             "version": "2.11.8",
             "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
             "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
         "node_modules/@popperjs/core": {
             "version": "2.11.8",
             "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
             "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+            "license": "MIT",
             "funding": {
                 "type": "opencollective",
                 "url": "https://opencollective.com/popperjs"
             }
         },
         "node_modules/@react-aria/ssr": {
             "funding": {
                 "type": "opencollective",
                 "url": "https://opencollective.com/popperjs"
             }
         },
         "node_modules/@react-aria/ssr": {
-            "version": "3.7.1",
-            "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.1.tgz",
-            "integrity": "sha512-ovVPSD1WlRpZHt7GI9DqJrWG3OIYS+NXQ9y5HIewMJpSe+jPQmMQfyRmgX4EnvmxSlp0u04Wg/7oItcoSIb/RA==",
+            "version": "3.9.9",
+            "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.9.tgz",
+            "integrity": "sha512-2P5thfjfPy/np18e5wD4WPt8ydNXhij1jwA8oehxZTFqlgVMGXzcWKxTb4RtJrLFsqPO7RUQTiY8QJk0M4Vy2g==",
+            "license": "Apache-2.0",
             "dependencies": {
                 "@swc/helpers": "^0.5.0"
             },
             "dependencies": {
                 "@swc/helpers": "^0.5.0"
             },
                 "node": ">= 12"
             },
             "peerDependencies": {
                 "node": ">= 12"
             },
             "peerDependencies": {
-                "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0"
+                "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
             }
         },
         "node_modules/@remix-run/router": {
             }
         },
         "node_modules/@remix-run/router": {
-            "version": "1.8.0",
-            "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz",
-            "integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg==",
+            "version": "1.23.0",
+            "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz",
+            "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==",
+            "license": "MIT",
             "engines": {
                 "node": ">=14.0.0"
             }
         },
         "node_modules/@restart/hooks": {
             "engines": {
                 "node": ">=14.0.0"
             }
         },
         "node_modules/@restart/hooks": {
-            "version": "0.4.11",
-            "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz",
-            "integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==",
+            "version": "0.4.16",
+            "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz",
+            "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==",
+            "license": "MIT",
             "dependencies": {
                 "dequal": "^2.0.3"
             },
             "dependencies": {
                 "dequal": "^2.0.3"
             },
             }
         },
         "node_modules/@restart/ui": {
             }
         },
         "node_modules/@restart/ui": {
-            "version": "1.6.6",
-            "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz",
-            "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==",
+            "version": "1.9.4",
+            "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz",
+            "integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/runtime": "^7.21.0",
-                "@popperjs/core": "^2.11.6",
+                "@babel/runtime": "^7.26.0",
+                "@popperjs/core": "^2.11.8",
                 "@react-aria/ssr": "^3.5.0",
                 "@react-aria/ssr": "^3.5.0",
-                "@restart/hooks": "^0.4.9",
-                "@types/warning": "^3.0.0",
+                "@restart/hooks": "^0.5.0",
+                "@types/warning": "^3.0.3",
                 "dequal": "^2.0.3",
                 "dom-helpers": "^5.2.0",
                 "dequal": "^2.0.3",
                 "dom-helpers": "^5.2.0",
-                "uncontrollable": "^8.0.1",
+                "uncontrollable": "^8.0.4",
                 "warning": "^4.0.3"
             },
             "peerDependencies": {
                 "warning": "^4.0.3"
             },
             "peerDependencies": {
                 "react-dom": ">=16.14.0"
             }
         },
                 "react-dom": ">=16.14.0"
             }
         },
+        "node_modules/@restart/ui/node_modules/@restart/hooks": {
+            "version": "0.5.1",
+            "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz",
+            "integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==",
+            "license": "MIT",
+            "dependencies": {
+                "dequal": "^2.0.3"
+            },
+            "peerDependencies": {
+                "react": ">=16.8.0"
+            }
+        },
         "node_modules/@restart/ui/node_modules/uncontrollable": {
             "version": "8.0.4",
             "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
             "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
         "node_modules/@restart/ui/node_modules/uncontrollable": {
             "version": "8.0.4",
             "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
             "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
+            "license": "MIT",
             "peerDependencies": {
                 "react": ">=16.14.0"
             }
         },
             "peerDependencies": {
                 "react": ">=16.14.0"
             }
         },
-        "node_modules/@sinclair/typebox": {
-            "version": "0.27.8",
-            "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
-            "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
-            "dev": true
-        },
-        "node_modules/@sinonjs/commons": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
-            "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
+        "node_modules/@rolldown/pluginutils": {
+            "version": "1.0.0-beta.11",
+            "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11.tgz",
+            "integrity": "sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "type-detect": "4.0.8"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/@sinonjs/fake-timers": {
-            "version": "10.3.0",
-            "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
-            "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+        "node_modules/@rollup/plugin-alias": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz",
+            "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@sinonjs/commons": "^3.0.0"
-            }
-        },
-        "node_modules/@swc/helpers": {
-            "version": "0.5.1",
-            "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz",
-            "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==",
-            "dependencies": {
-                "tslib": "^2.4.0"
+            "license": "MIT",
+            "engines": {
+                "node": ">=14.0.0"
+            },
+            "peerDependencies": {
+                "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+            },
+            "peerDependenciesMeta": {
+                "rollup": {
+                    "optional": true
+                }
             }
         },
             }
         },
-        "node_modules/@tailwindcss/forms": {
-            "version": "0.5.6",
-            "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz",
-            "integrity": "sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==",
+        "node_modules/@rollup/pluginutils": {
+            "version": "5.2.0",
+            "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz",
+            "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "mini-svg-data-uri": "^1.2.3"
+                "@types/estree": "^1.0.0",
+                "estree-walker": "^2.0.2",
+                "picomatch": "^4.0.2"
+            },
+            "engines": {
+                "node": ">=14.0.0"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1"
+                "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+            },
+            "peerDependenciesMeta": {
+                "rollup": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@rollup/pluginutils/node_modules/picomatch": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+            "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/jonschlinkert"
+            }
+        },
+        "node_modules/@rollup/rollup-android-arm-eabi": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz",
+            "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ]
+        },
+        "node_modules/@rollup/rollup-android-arm64": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz",
+            "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "android"
+            ]
+        },
+        "node_modules/@rollup/rollup-darwin-arm64": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz",
+            "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ]
+        },
+        "node_modules/@rollup/rollup-darwin-x64": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz",
+            "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "darwin"
+            ]
+        },
+        "node_modules/@rollup/rollup-freebsd-arm64": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz",
+            "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ]
+        },
+        "node_modules/@rollup/rollup-freebsd-x64": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz",
+            "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "freebsd"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz",
+            "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz",
+            "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==",
+            "cpu": [
+                "arm"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-arm64-gnu": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz",
+            "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-arm64-musl": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz",
+            "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz",
+            "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==",
+            "cpu": [
+                "loong64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz",
+            "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==",
+            "cpu": [
+                "ppc64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz",
+            "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==",
+            "cpu": [
+                "riscv64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-riscv64-musl": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz",
+            "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==",
+            "cpu": [
+                "riscv64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-s390x-gnu": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz",
+            "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==",
+            "cpu": [
+                "s390x"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-x64-gnu": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz",
+            "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-linux-x64-musl": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz",
+            "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "linux"
+            ]
+        },
+        "node_modules/@rollup/rollup-win32-arm64-msvc": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz",
+            "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==",
+            "cpu": [
+                "arm64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ]
+        },
+        "node_modules/@rollup/rollup-win32-ia32-msvc": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz",
+            "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==",
+            "cpu": [
+                "ia32"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ]
+        },
+        "node_modules/@rollup/rollup-win32-x64-msvc": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz",
+            "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==",
+            "cpu": [
+                "x64"
+            ],
+            "dev": true,
+            "license": "MIT",
+            "optional": true,
+            "os": [
+                "win32"
+            ]
+        },
+        "node_modules/@rtsao/scc": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
+            "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/@swc/helpers": {
+            "version": "0.5.17",
+            "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
+            "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
+            "license": "Apache-2.0",
+            "dependencies": {
+                "tslib": "^2.8.0"
+            }
+        },
+        "node_modules/@tailwindcss/forms": {
+            "version": "0.5.10",
+            "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",
+            "integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "mini-svg-data-uri": "^1.2.3"
+            },
+            "peerDependencies": {
+                "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1"
             }
         },
         "node_modules/@testing-library/dom": {
             }
         },
         "node_modules/@testing-library/dom": {
-            "version": "9.3.4",
-            "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz",
-            "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==",
+            "version": "10.4.0",
+            "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
+            "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
                 "@babel/code-frame": "^7.10.4",
                 "@babel/runtime": "^7.12.5",
                 "@types/aria-query": "^5.0.1",
             "dependencies": {
                 "@babel/code-frame": "^7.10.4",
                 "@babel/runtime": "^7.12.5",
                 "@types/aria-query": "^5.0.1",
-                "aria-query": "5.1.3",
+                "aria-query": "5.3.0",
                 "chalk": "^4.1.0",
                 "dom-accessibility-api": "^0.5.9",
                 "lz-string": "^1.5.0",
                 "pretty-format": "^27.0.2"
             },
             "engines": {
                 "chalk": "^4.1.0",
                 "dom-accessibility-api": "^0.5.9",
                 "lz-string": "^1.5.0",
                 "pretty-format": "^27.0.2"
             },
             "engines": {
-                "node": ">=14"
-            }
-        },
-        "node_modules/@testing-library/dom/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">=18"
             }
         },
         "node_modules/@testing-library/dom/node_modules/aria-query": {
             }
         },
         "node_modules/@testing-library/dom/node_modules/aria-query": {
-            "version": "5.1.3",
-            "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
-            "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
+            "version": "5.3.0",
+            "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+            "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "deep-equal": "^2.0.5"
+                "dequal": "^2.0.3"
             }
         },
         "node_modules/@testing-library/dom/node_modules/chalk": {
             }
         },
         "node_modules/@testing-library/dom/node_modules/chalk": {
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
             "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
             "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
                 "ansi-styles": "^4.1.0",
                 "supports-color": "^7.1.0"
             "dependencies": {
                 "ansi-styles": "^4.1.0",
                 "supports-color": "^7.1.0"
                 "url": "https://github.com/chalk/chalk?sponsor=1"
             }
         },
                 "url": "https://github.com/chalk/chalk?sponsor=1"
             }
         },
-        "node_modules/@testing-library/dom/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-            "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/@testing-library/dom/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
         "node_modules/@testing-library/dom/node_modules/dom-accessibility-api": {
             "version": "0.5.16",
             "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
             "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
         "node_modules/@testing-library/dom/node_modules/dom-accessibility-api": {
             "version": "0.5.16",
             "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
             "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
-            "dev": true
-        },
-        "node_modules/@testing-library/dom/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/@testing-library/dom/node_modules/pretty-format": {
-            "version": "27.5.1",
-            "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
-            "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
-            "dev": true,
-            "dependencies": {
-                "ansi-regex": "^5.0.1",
-                "ansi-styles": "^5.0.0",
-                "react-is": "^17.0.1"
-            },
-            "engines": {
-                "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
-            }
-        },
-        "node_modules/@testing-library/dom/node_modules/pretty-format/node_modules/ansi-styles": {
-            "version": "5.2.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
-            "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
-            "dev": true,
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-            }
-        },
-        "node_modules/@testing-library/dom/node_modules/react-is": {
-            "version": "17.0.2",
-            "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
-            "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
-            "dev": true
-        },
-        "node_modules/@testing-library/dom/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
+            "license": "MIT",
+            "peer": true
         },
         "node_modules/@testing-library/jest-dom": {
         },
         "node_modules/@testing-library/jest-dom": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz",
-            "integrity": "sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==",
+            "version": "6.6.3",
+            "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz",
+            "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@adobe/css-tools": "^4.3.2",
-                "@babel/runtime": "^7.9.2",
+                "@adobe/css-tools": "^4.4.0",
                 "aria-query": "^5.0.0",
                 "chalk": "^3.0.0",
                 "css.escape": "^1.5.1",
                 "dom-accessibility-api": "^0.6.3",
                 "aria-query": "^5.0.0",
                 "chalk": "^3.0.0",
                 "css.escape": "^1.5.1",
                 "dom-accessibility-api": "^0.6.3",
-                "lodash": "^4.17.15",
+                "lodash": "^4.17.21",
                 "redent": "^3.0.0"
             },
             "engines": {
                 "node": ">=14",
                 "npm": ">=6",
                 "yarn": ">=1"
                 "redent": "^3.0.0"
             },
             "engines": {
                 "node": ">=14",
                 "npm": ">=6",
                 "yarn": ">=1"
+            }
+        },
+        "node_modules/@testing-library/react": {
+            "version": "16.3.0",
+            "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz",
+            "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@babel/runtime": "^7.12.5"
+            },
+            "engines": {
+                "node": ">=18"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "@jest/globals": ">= 28",
-                "@types/bun": "latest",
-                "@types/jest": ">= 28",
-                "jest": ">= 28",
-                "vitest": ">= 0.32"
+                "@testing-library/dom": "^10.0.0",
+                "@types/react": "^18.0.0 || ^19.0.0",
+                "@types/react-dom": "^18.0.0 || ^19.0.0",
+                "react": "^18.0.0 || ^19.0.0",
+                "react-dom": "^18.0.0 || ^19.0.0"
             },
             "peerDependenciesMeta": {
             },
             "peerDependenciesMeta": {
-                "@jest/globals": {
-                    "optional": true
-                },
-                "@types/bun": {
-                    "optional": true
-                },
-                "@types/jest": {
-                    "optional": true
-                },
-                "jest": {
+                "@types/react": {
                     "optional": true
                 },
                     "optional": true
                 },
-                "vitest": {
+                "@types/react-dom": {
                     "optional": true
                 }
             }
         },
                     "optional": true
                 }
             }
         },
-        "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-            }
-        },
-        "node_modules/@testing-library/jest-dom/node_modules/chalk": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-            "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-            "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/@testing-library/jest-dom/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-            "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/@testing-library/jest-dom/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/@testing-library/jest-dom/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/@testing-library/jest-dom/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-            "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/@testing-library/react": {
-            "version": "14.2.1",
-            "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.1.tgz",
-            "integrity": "sha512-sGdjws32ai5TLerhvzThYFbpnF9XtL65Cjf+gB0Dhr29BGqK+mAeN7SURSdu+eqgET4ANcWoC7FQpkaiGvBr+A==",
-            "dev": true,
-            "dependencies": {
-                "@babel/runtime": "^7.12.5",
-                "@testing-library/dom": "^9.0.0",
-                "@types/react-dom": "^18.0.0"
-            },
-            "engines": {
-                "node": ">=14"
-            },
-            "peerDependencies": {
-                "react": "^18.0.0",
-                "react-dom": "^18.0.0"
-            }
-        },
-        "node_modules/@tootallnate/once": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
-            "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
-            "dev": true,
-            "engines": {
-                "node": ">= 10"
-            }
-        },
-        "node_modules/@trysound/sax": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
-            "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
+        "node_modules/@trysound/sax": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
+            "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "engines": {
                 "node": ">=10.13.0"
             }
             "engines": {
                 "node": ">=10.13.0"
             }
             "version": "5.0.4",
             "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
             "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
             "version": "5.0.4",
             "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
             "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "peer": true
         },
         "node_modules/@types/babel__core": {
         },
         "node_modules/@types/babel__core": {
-            "version": "7.20.1",
-            "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz",
-            "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==",
+            "version": "7.20.5",
+            "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+            "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/parser": "^7.20.7",
                 "@babel/types": "^7.20.7",
             "dependencies": {
                 "@babel/parser": "^7.20.7",
                 "@babel/types": "^7.20.7",
             }
         },
         "node_modules/@types/babel__generator": {
             }
         },
         "node_modules/@types/babel__generator": {
-            "version": "7.6.4",
-            "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz",
-            "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==",
+            "version": "7.27.0",
+            "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
+            "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/types": "^7.0.0"
             }
         },
         "node_modules/@types/babel__template": {
             "dependencies": {
                 "@babel/types": "^7.0.0"
             }
         },
         "node_modules/@types/babel__template": {
-            "version": "7.4.1",
-            "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
-            "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==",
+            "version": "7.4.4",
+            "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+            "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/parser": "^7.1.0",
                 "@babel/types": "^7.0.0"
             }
         },
         "node_modules/@types/babel__traverse": {
             "dependencies": {
                 "@babel/parser": "^7.1.0",
                 "@babel/types": "^7.0.0"
             }
         },
         "node_modules/@types/babel__traverse": {
-            "version": "7.20.1",
-            "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz",
-            "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==",
+            "version": "7.20.7",
+            "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz",
+            "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/types": "^7.20.7"
             }
         },
         "node_modules/@types/body-parser": {
             "dependencies": {
                 "@babel/types": "^7.20.7"
             }
         },
         "node_modules/@types/body-parser": {
-            "version": "1.19.2",
-            "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
-            "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
+            "version": "1.19.6",
+            "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
+            "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/connect": "*",
                 "@types/node": "*"
             }
         },
         "node_modules/@types/bonjour": {
             "dependencies": {
                 "@types/connect": "*",
                 "@types/node": "*"
             }
         },
         "node_modules/@types/bonjour": {
-            "version": "3.5.10",
-            "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz",
-            "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==",
+            "version": "3.5.13",
+            "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz",
+            "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*"
             }
         },
             "dependencies": {
                 "@types/node": "*"
             }
         },
+        "node_modules/@types/chai": {
+            "version": "5.2.2",
+            "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz",
+            "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/deep-eql": "*"
+            }
+        },
         "node_modules/@types/clean-css": {
         "node_modules/@types/clean-css": {
-            "version": "4.2.7",
-            "resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-4.2.7.tgz",
-            "integrity": "sha512-lcoZHjUAANLTACLGi+O/0pN+oKQAQ8zAMWJSxiBRNLxqZG/WE8hfXJUs1eYwJOvOnDJrvxU1kR77UiVJ3+9N0Q==",
+            "version": "4.2.11",
+            "resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-4.2.11.tgz",
+            "integrity": "sha512-Y8n81lQVTAfP2TOdtJJEsCoYl1AnOkqDqMvXb9/7pfgZZ7r8YrEyurrAvAoAjHOGXKRybay+5CsExqIH6liccw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*",
                 "source-map": "^0.6.0"
             }
         },
         "node_modules/@types/connect": {
             "dependencies": {
                 "@types/node": "*",
                 "source-map": "^0.6.0"
             }
         },
         "node_modules/@types/connect": {
-            "version": "3.4.36",
-            "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz",
-            "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==",
+            "version": "3.4.38",
+            "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+            "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*"
             }
         },
         "node_modules/@types/connect-history-api-fallback": {
             "dependencies": {
                 "@types/node": "*"
             }
         },
         "node_modules/@types/connect-history-api-fallback": {
-            "version": "1.5.1",
-            "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.1.tgz",
-            "integrity": "sha512-iaQslNbARe8fctL5Lk+DsmgWOM83lM+7FzP0eQUJs1jd3kBE8NWqBTIT2S8SqQOJjxvt2eyIjpOuYeRXq2AdMw==",
+            "version": "1.5.4",
+            "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz",
+            "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/express-serve-static-core": "*",
                 "@types/node": "*"
             }
         },
         "node_modules/@types/d3-array": {
             "dependencies": {
                 "@types/express-serve-static-core": "*",
                 "@types/node": "*"
             }
         },
         "node_modules/@types/d3-array": {
-            "version": "3.0.7",
-            "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.7.tgz",
-            "integrity": "sha512-4/Q0FckQ8TBjsB0VdGFemJOG8BLXUB2KKlL0VmZ+eOYeOnTb/wDRQqYWpBmQ6IlvWkXwkYiot+n9Px2aTJ7zGQ=="
+            "version": "3.2.1",
+            "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz",
+            "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==",
+            "license": "MIT"
         },
         "node_modules/@types/d3-color": {
         },
         "node_modules/@types/d3-color": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz",
-            "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA=="
+            "version": "3.1.3",
+            "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+            "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
+            "license": "MIT"
         },
         "node_modules/@types/d3-ease": {
         },
         "node_modules/@types/d3-ease": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz",
-            "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA=="
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+            "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
+            "license": "MIT"
         },
         "node_modules/@types/d3-interpolate": {
         },
         "node_modules/@types/d3-interpolate": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
-            "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==",
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+            "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+            "license": "MIT",
             "dependencies": {
                 "@types/d3-color": "*"
             }
         },
         "node_modules/@types/d3-path": {
             "dependencies": {
                 "@types/d3-color": "*"
             }
         },
         "node_modules/@types/d3-path": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz",
-            "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg=="
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+            "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
+            "license": "MIT"
         },
         "node_modules/@types/d3-scale": {
         },
         "node_modules/@types/d3-scale": {
-            "version": "4.0.4",
-            "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.4.tgz",
-            "integrity": "sha512-eq1ZeTj0yr72L8MQk6N6heP603ubnywSDRfNpi5enouR112HzGLS6RIvExCzZTraFF4HdzNpJMwA/zGiMoHUUw==",
+            "version": "4.0.9",
+            "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+            "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+            "license": "MIT",
             "dependencies": {
                 "@types/d3-time": "*"
             }
         },
         "node_modules/@types/d3-shape": {
             "dependencies": {
                 "@types/d3-time": "*"
             }
         },
         "node_modules/@types/d3-shape": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.2.tgz",
-            "integrity": "sha512-NN4CXr3qeOUNyK5WasVUV8NCSAx/CRVcwcb0BuuS1PiTqwIm6ABi1SyasLZ/vsVCFDArF+W4QiGzSry1eKYQ7w==",
+            "version": "3.1.7",
+            "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
+            "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
+            "license": "MIT",
             "dependencies": {
                 "@types/d3-path": "*"
             }
         },
         "node_modules/@types/d3-time": {
             "dependencies": {
                 "@types/d3-path": "*"
             }
         },
         "node_modules/@types/d3-time": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz",
-            "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg=="
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+            "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
+            "license": "MIT"
         },
         "node_modules/@types/d3-timer": {
         },
         "node_modules/@types/d3-timer": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz",
-            "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g=="
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+            "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
+            "license": "MIT"
+        },
+        "node_modules/@types/deep-eql": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
+            "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/eslint": {
         },
         "node_modules/@types/eslint": {
-            "version": "8.44.2",
-            "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz",
-            "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==",
+            "version": "9.6.1",
+            "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
+            "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/estree": "*",
                 "@types/json-schema": "*"
             }
         },
         "node_modules/@types/eslint-scope": {
             "dependencies": {
                 "@types/estree": "*",
                 "@types/json-schema": "*"
             }
         },
         "node_modules/@types/eslint-scope": {
-            "version": "3.7.4",
-            "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
-            "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
+            "version": "3.7.7",
+            "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+            "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/eslint": "*",
                 "@types/estree": "*"
             }
         },
         "node_modules/@types/estree": {
             "dependencies": {
                 "@types/eslint": "*",
                 "@types/estree": "*"
             }
         },
         "node_modules/@types/estree": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
-            "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
-            "dev": true
+            "version": "1.0.8",
+            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+            "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/express": {
         },
         "node_modules/@types/express": {
-            "version": "4.17.17",
-            "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
-            "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
+            "version": "4.17.23",
+            "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz",
+            "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/body-parser": "*",
                 "@types/express-serve-static-core": "^4.17.33",
             "dependencies": {
                 "@types/body-parser": "*",
                 "@types/express-serve-static-core": "^4.17.33",
             }
         },
         "node_modules/@types/express-serve-static-core": {
             }
         },
         "node_modules/@types/express-serve-static-core": {
-            "version": "4.17.28",
-            "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
-            "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
+            "version": "5.0.6",
+            "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.6.tgz",
+            "integrity": "sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*",
                 "@types/qs": "*",
             "dependencies": {
                 "@types/node": "*",
                 "@types/qs": "*",
-                "@types/range-parser": "*"
+                "@types/range-parser": "*",
+                "@types/send": "*"
             }
         },
         "node_modules/@types/express/node_modules/@types/express-serve-static-core": {
             }
         },
         "node_modules/@types/express/node_modules/@types/express-serve-static-core": {
-            "version": "4.17.36",
-            "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.36.tgz",
-            "integrity": "sha512-zbivROJ0ZqLAtMzgzIUC4oNqDG9iF0lSsAqpOD9kbs5xcIM3dTiyuHvBc7R8MtWBp3AAWGaovJa+wzWPjLYW7Q==",
+            "version": "4.19.6",
+            "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
+            "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*",
                 "@types/qs": "*",
             "dependencies": {
                 "@types/node": "*",
                 "@types/qs": "*",
             "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
             "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
             "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/minimatch": "*",
                 "@types/node": "*"
             }
         },
             "dependencies": {
                 "@types/minimatch": "*",
                 "@types/node": "*"
             }
         },
-        "node_modules/@types/graceful-fs": {
-            "version": "4.1.9",
-            "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
-            "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
-            "dev": true,
+        "node_modules/@types/hoist-non-react-statics": {
+            "version": "3.3.6",
+            "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz",
+            "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@types/node": "*"
+                "@types/react": "*",
+                "hoist-non-react-statics": "^3.3.0"
             }
         },
         "node_modules/@types/http-errors": {
             }
         },
         "node_modules/@types/http-errors": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz",
-            "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==",
-            "dev": true
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+            "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/http-proxy": {
         },
         "node_modules/@types/http-proxy": {
-            "version": "1.17.11",
-            "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz",
-            "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==",
+            "version": "1.17.16",
+            "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz",
+            "integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*"
             }
         },
         "node_modules/@types/imagemin": {
             "dependencies": {
                 "@types/node": "*"
             }
         },
         "node_modules/@types/imagemin": {
-            "version": "8.0.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin/-/imagemin-8.0.1.tgz",
-            "integrity": "sha512-DSpM//dRPzme7doePGkmR1uoquHi0h0ElaA5qFnxHECfFcB8z/jhMI8eqmxWNpHn9ZG18p4PC918sZLhR0cr5A==",
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/@types/imagemin/-/imagemin-9.0.1.tgz",
+            "integrity": "sha512-xMWpvrUhtYxl6EeW+UhVH3rwUKhCRx21XddcoWByjDAasXZT5pQaCn0YVnXoTijX5hlTrGqV4TGQL/Htpp00+w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*"
             }
         },
         "node_modules/@types/imagemin-gifsicle": {
             "dependencies": {
                 "@types/node": "*"
             }
         },
         "node_modules/@types/imagemin-gifsicle": {
-            "version": "7.0.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin-gifsicle/-/imagemin-gifsicle-7.0.1.tgz",
-            "integrity": "sha512-kUz6sUh0P95JOS0RGEaaemWUrASuw+dLsWIveK2UZJx74id/B9epgblMkCk/r5MjUWbZ83wFvacG5Rb/f97gyA==",
+            "version": "7.0.4",
+            "resolved": "https://registry.npmjs.org/@types/imagemin-gifsicle/-/imagemin-gifsicle-7.0.4.tgz",
+            "integrity": "sha512-ZghMBd/Jgqg5utTJNPmvf6DkuHzMhscJ8vgf/7MUGCpO+G+cLrhYltL+5d+h3A1B4W73S2SrmJZ1jS5LACpX+A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/imagemin": "*"
             }
         },
         "node_modules/@types/imagemin-mozjpeg": {
             "dependencies": {
                 "@types/imagemin": "*"
             }
         },
         "node_modules/@types/imagemin-mozjpeg": {
-            "version": "8.0.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin-mozjpeg/-/imagemin-mozjpeg-8.0.1.tgz",
-            "integrity": "sha512-kMQWEoKxxhlnH4POI3qfW9DjXlQfi80ux3l2b3j5R3eudSCoUIzKQLkfMjNJ6eMYnMWBcB+rfQOWqIzdIwFGKw==",
+            "version": "8.0.4",
+            "resolved": "https://registry.npmjs.org/@types/imagemin-mozjpeg/-/imagemin-mozjpeg-8.0.4.tgz",
+            "integrity": "sha512-ZCAxV8SYJB8ehwHpnbRpHjg5Wc4HcyuAMiDhXbkgC7gujDoOTyHO3dhDkUtZ1oK1DLBRZapqG9etdLVhUml7yQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/imagemin": "*"
             }
         },
         "node_modules/@types/imagemin-optipng": {
             "dependencies": {
                 "@types/imagemin": "*"
             }
         },
         "node_modules/@types/imagemin-optipng": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin-optipng/-/imagemin-optipng-5.2.1.tgz",
-            "integrity": "sha512-XCM/3q+HUL7v4zOqMI+dJ5dTxT+MUukY9KU49DSnYb/4yWtSMHJyADP+WHSMVzTR63J2ZvfUOzSilzBNEQW78g==",
+            "version": "5.2.4",
+            "resolved": "https://registry.npmjs.org/@types/imagemin-optipng/-/imagemin-optipng-5.2.4.tgz",
+            "integrity": "sha512-mvKnDMC8eCYZetAQudjs1DbgpR84WhsTx1wgvdiXnpuUEti3oJ+MaMYBRWPY0JlQ4+y4TXKOfa7+LOuT8daegQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/imagemin": "*"
             }
             "dependencies": {
                 "@types/imagemin": "*"
             }
             "resolved": "https://registry.npmjs.org/@types/imagemin-svgo/-/imagemin-svgo-8.0.1.tgz",
             "integrity": "sha512-YafkdrVAcr38U0Ln1C+L1n4SIZqC47VBHTyxCq7gTUSd1R9MdIvMcrljWlgU1M9O68WZDeQWUrKipKYfEOCOvQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@types/imagemin-svgo/-/imagemin-svgo-8.0.1.tgz",
             "integrity": "sha512-YafkdrVAcr38U0Ln1C+L1n4SIZqC47VBHTyxCq7gTUSd1R9MdIvMcrljWlgU1M9O68WZDeQWUrKipKYfEOCOvQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/imagemin": "*",
                 "@types/svgo": "^1"
             }
         },
             "dependencies": {
                 "@types/imagemin": "*",
                 "@types/svgo": "^1"
             }
         },
-        "node_modules/@types/istanbul-lib-coverage": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
-            "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
-            "dev": true
-        },
-        "node_modules/@types/istanbul-lib-report": {
-            "version": "3.0.3",
-            "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
-            "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
-            "dev": true,
-            "dependencies": {
-                "@types/istanbul-lib-coverage": "*"
-            }
-        },
-        "node_modules/@types/istanbul-reports": {
-            "version": "3.0.4",
-            "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
-            "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
-            "dev": true,
-            "dependencies": {
-                "@types/istanbul-lib-report": "*"
-            }
-        },
-        "node_modules/@types/jsdom": {
-            "version": "20.0.1",
-            "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz",
-            "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==",
-            "dev": true,
-            "dependencies": {
-                "@types/node": "*",
-                "@types/tough-cookie": "*",
-                "parse5": "^7.0.0"
-            }
-        },
         "node_modules/@types/json-schema": {
         "node_modules/@types/json-schema": {
-            "version": "7.0.12",
-            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
-            "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==",
-            "dev": true
+            "version": "7.0.15",
+            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+            "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/json5": {
             "version": "0.0.29",
             "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
             "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
         },
         "node_modules/@types/json5": {
             "version": "0.0.29",
             "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
             "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/mime": {
         },
         "node_modules/@types/mime": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
-            "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==",
-            "dev": true
+            "version": "1.3.5",
+            "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+            "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/minimatch": {
             "version": "5.1.2",
             "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
             "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
         },
         "node_modules/@types/minimatch": {
             "version": "5.1.2",
             "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
             "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/node": {
         },
         "node_modules/@types/node": {
-            "version": "20.5.9",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz",
-            "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==",
-            "dev": true
+            "version": "24.0.3",
+            "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz",
+            "integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "undici-types": "~7.8.0"
+            }
+        },
+        "node_modules/@types/node-forge": {
+            "version": "1.3.11",
+            "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz",
+            "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/node": "*"
+            }
         },
         "node_modules/@types/parse-json": {
         },
         "node_modules/@types/parse-json": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
-            "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
-            "dev": true
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
+            "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/prop-types": {
         },
         "node_modules/@types/prop-types": {
-            "version": "15.7.5",
-            "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
-            "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
+            "version": "15.7.15",
+            "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
+            "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
+            "license": "MIT"
         },
         "node_modules/@types/qs": {
         },
         "node_modules/@types/qs": {
-            "version": "6.9.8",
-            "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz",
-            "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==",
-            "dev": true
+            "version": "6.14.0",
+            "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
+            "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/range-parser": {
         },
         "node_modules/@types/range-parser": {
-            "version": "1.2.4",
-            "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
-            "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
-            "dev": true
+            "version": "1.2.7",
+            "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+            "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/react": {
         },
         "node_modules/@types/react": {
-            "version": "18.2.21",
-            "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz",
-            "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==",
+            "version": "18.3.23",
+            "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz",
+            "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==",
+            "license": "MIT",
             "dependencies": {
                 "@types/prop-types": "*",
             "dependencies": {
                 "@types/prop-types": "*",
-                "@types/scheduler": "*",
                 "csstype": "^3.0.2"
             }
         },
         "node_modules/@types/react-dom": {
                 "csstype": "^3.0.2"
             }
         },
         "node_modules/@types/react-dom": {
-            "version": "18.2.19",
-            "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.19.tgz",
-            "integrity": "sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA==",
+            "version": "18.3.7",
+            "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
+            "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@types/react": "*"
+            "license": "MIT",
+            "optional": true,
+            "peer": true,
+            "peerDependencies": {
+                "@types/react": "^18.0.0"
             }
         },
         "node_modules/@types/react-transition-group": {
             }
         },
         "node_modules/@types/react-transition-group": {
-            "version": "4.4.6",
-            "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz",
-            "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==",
-            "dependencies": {
+            "version": "4.4.12",
+            "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
+            "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
+            "license": "MIT",
+            "peerDependencies": {
                 "@types/react": "*"
             }
         },
                 "@types/react": "*"
             }
         },
             "version": "0.12.0",
             "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
             "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
             "version": "0.12.0",
             "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
             "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
-            "dev": true
-        },
-        "node_modules/@types/scheduler": {
-            "version": "0.16.3",
-            "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
-            "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/send": {
         },
         "node_modules/@types/send": {
-            "version": "0.17.1",
-            "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
-            "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==",
+            "version": "0.17.5",
+            "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
+            "integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/mime": "^1",
                 "@types/node": "*"
             }
         },
             "dependencies": {
                 "@types/mime": "^1",
                 "@types/node": "*"
             }
         },
-        "node_modules/@types/send/node_modules/@types/mime": {
-            "version": "1.3.2",
-            "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
-            "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
-            "dev": true
-        },
         "node_modules/@types/serve-index": {
         "node_modules/@types/serve-index": {
-            "version": "1.9.1",
-            "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
-            "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==",
+            "version": "1.9.4",
+            "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz",
+            "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/express": "*"
             }
         },
         "node_modules/@types/serve-static": {
             "dependencies": {
                 "@types/express": "*"
             }
         },
         "node_modules/@types/serve-static": {
-            "version": "1.15.2",
-            "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz",
-            "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==",
+            "version": "1.15.8",
+            "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz",
+            "integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/http-errors": "*",
             "dependencies": {
                 "@types/http-errors": "*",
-                "@types/mime": "*",
-                "@types/node": "*"
+                "@types/node": "*",
+                "@types/send": "*"
             }
         },
         "node_modules/@types/sockjs": {
             }
         },
         "node_modules/@types/sockjs": {
-            "version": "0.3.33",
-            "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz",
-            "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==",
+            "version": "0.3.36",
+            "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz",
+            "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*"
             }
         },
             "dependencies": {
                 "@types/node": "*"
             }
         },
-        "node_modules/@types/stack-utils": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
-            "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
-            "dev": true
-        },
         "node_modules/@types/svgo": {
             "version": "1.3.6",
             "resolved": "https://registry.npmjs.org/@types/svgo/-/svgo-1.3.6.tgz",
             "integrity": "sha512-AZU7vQcy/4WFEuwnwsNsJnFwupIpbllH1++LXScN6uxT1Z4zPzdrWG97w4/I7eFKFTvfy/bHFStWjdBAg2Vjug==",
         "node_modules/@types/svgo": {
             "version": "1.3.6",
             "resolved": "https://registry.npmjs.org/@types/svgo/-/svgo-1.3.6.tgz",
             "integrity": "sha512-AZU7vQcy/4WFEuwnwsNsJnFwupIpbllH1++LXScN6uxT1Z4zPzdrWG97w4/I7eFKFTvfy/bHFStWjdBAg2Vjug==",
-            "dev": true
-        },
-        "node_modules/@types/tough-cookie": {
-            "version": "4.0.5",
-            "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
-            "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@types/warning": {
         },
         "node_modules/@types/warning": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
-            "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA=="
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
+            "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==",
+            "license": "MIT"
         },
         "node_modules/@types/ws": {
         },
         "node_modules/@types/ws": {
-            "version": "8.5.5",
-            "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz",
-            "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==",
+            "version": "8.18.1",
+            "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
+            "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/node": "*"
             }
         },
             "dependencies": {
                 "@types/node": "*"
             }
         },
-        "node_modules/@types/yargs": {
-            "version": "17.0.32",
-            "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
-            "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==",
-            "dev": true,
-            "dependencies": {
-                "@types/yargs-parser": "*"
-            }
-        },
-        "node_modules/@types/yargs-parser": {
-            "version": "21.0.3",
-            "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
-            "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
-            "dev": true
-        },
         "node_modules/@uiw/codemirror-extensions-basic-setup": {
         "node_modules/@uiw/codemirror-extensions-basic-setup": {
-            "version": "4.21.13",
-            "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.21.13.tgz",
-            "integrity": "sha512-5ObHaBqPV00xBVleDFehzPfOQvek5dPM7YLdPHJUE9bumeSflIWJb55n0Zg/w1rsuU0Lt/Q6WJUh4X6VGR1FVw==",
+            "version": "4.23.13",
+            "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.23.13.tgz",
+            "integrity": "sha512-U1CnDFpq6ydNqrRDS5Bdnvgso8ezwwbrmKvmAD3hmoVyRDsDU6HTtmcV+w0rZ3kElUCkKI5lY0DMvTTQ4+L3RQ==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/commands": "^6.0.0",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/commands": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
                 "@codemirror/view": "^6.0.0"
             },
                 "@codemirror/state": "^6.0.0",
                 "@codemirror/view": "^6.0.0"
             },
+            "funding": {
+                "url": "https://jaywcjlove.github.io/#/sponsor"
+            },
             "peerDependencies": {
                 "@codemirror/autocomplete": ">=6.0.0",
                 "@codemirror/commands": ">=6.0.0",
             "peerDependencies": {
                 "@codemirror/autocomplete": ">=6.0.0",
                 "@codemirror/commands": ">=6.0.0",
             }
         },
         "node_modules/@uiw/codemirror-theme-github": {
             }
         },
         "node_modules/@uiw/codemirror-theme-github": {
-            "version": "4.21.13",
-            "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-github/-/codemirror-theme-github-4.21.13.tgz",
-            "integrity": "sha512-UblpWrkb+epGSrhf8ztuDO75+GOD8Otf7I/saM3lUzipdeKBOSC7Q7o7De36xbF1HpfOUYbqsajo1X3INf8Y7A==",
+            "version": "4.23.13",
+            "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-github/-/codemirror-theme-github-4.23.13.tgz",
+            "integrity": "sha512-e75jgCl6Zf7sC63ntyl4r2GU6ekqKbyfIB4g6EnneQlIzJQiDTM+mU0/pDR5hLTyGQdxQpcDs9EmDqfEyejGSQ==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@uiw/codemirror-themes": "4.21.13"
+                "@uiw/codemirror-themes": "4.23.13"
+            },
+            "funding": {
+                "url": "https://jaywcjlove.github.io/#/sponsor"
             }
         },
         "node_modules/@uiw/codemirror-themes": {
             }
         },
         "node_modules/@uiw/codemirror-themes": {
-            "version": "4.21.13",
-            "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.21.13.tgz",
-            "integrity": "sha512-+IeYow6kmz1LJmXd1rL7ngVxb5lm2wKrjYNfomDvmoUz2gKcca8y7pWGMIFhIsabrNW11SFVSloVkj9ZXw7e1Q==",
+            "version": "4.23.13",
+            "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.23.13.tgz",
+            "integrity": "sha512-thk4X8VNl15XPoDiOXdkeMAIIHQOoc5lPfmgOvrhPXHzt4zvH5efLWBw3zgpwuOWF+Uk6sYrS0eumtsSO/kgcA==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/language": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
                 "@codemirror/view": "^6.0.0"
             },
             "dependencies": {
                 "@codemirror/language": "^6.0.0",
                 "@codemirror/state": "^6.0.0",
                 "@codemirror/view": "^6.0.0"
             },
+            "funding": {
+                "url": "https://jaywcjlove.github.io/#/sponsor"
+            },
             "peerDependencies": {
                 "@codemirror/language": ">=6.0.0",
                 "@codemirror/state": ">=6.0.0",
             "peerDependencies": {
                 "@codemirror/language": ">=6.0.0",
                 "@codemirror/state": ">=6.0.0",
             }
         },
         "node_modules/@uiw/react-codemirror": {
             }
         },
         "node_modules/@uiw/react-codemirror": {
-            "version": "4.21.13",
-            "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.21.13.tgz",
-            "integrity": "sha512-kNX8jLeoDrF2CDa5lsey0MXjBXN3JP00z6AQTTP58mHvlE7Rf03QJSs7bNwwco+3kpwREifFJjnwRe+Y3Gmwtw==",
+            "version": "4.23.13",
+            "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.23.13.tgz",
+            "integrity": "sha512-y65ULzxOAfpxrA/8epoAOeCfmJXu9z0P62BbGOkITJTtU7WI59KfPbbwj35npSsMAkAmDE841qZo2I8jst/THg==",
+            "license": "MIT",
             "dependencies": {
                 "@babel/runtime": "^7.18.6",
                 "@codemirror/commands": "^6.1.0",
                 "@codemirror/state": "^6.1.1",
                 "@codemirror/theme-one-dark": "^6.0.0",
             "dependencies": {
                 "@babel/runtime": "^7.18.6",
                 "@codemirror/commands": "^6.1.0",
                 "@codemirror/state": "^6.1.1",
                 "@codemirror/theme-one-dark": "^6.0.0",
-                "@uiw/codemirror-extensions-basic-setup": "4.21.13",
+                "@uiw/codemirror-extensions-basic-setup": "4.23.13",
                 "codemirror": "^6.0.0"
             },
                 "codemirror": "^6.0.0"
             },
+            "funding": {
+                "url": "https://jaywcjlove.github.io/#/sponsor"
+            },
             "peerDependencies": {
                 "@babel/runtime": ">=7.11.0",
                 "@codemirror/state": ">=6.0.0",
             "peerDependencies": {
                 "@babel/runtime": ">=7.11.0",
                 "@codemirror/state": ">=6.0.0",
                 "react-dom": ">=16.8.0"
             }
         },
                 "react-dom": ">=16.8.0"
             }
         },
-        "node_modules/@vue/reactivity": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz",
-            "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==",
+        "node_modules/@vitejs/plugin-react": {
+            "version": "4.5.2",
+            "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.5.2.tgz",
+            "integrity": "sha512-QNVT3/Lxx99nMQWJWF7K4N6apUEuT0KlZA3mx/mVaoGj3smm/8rc8ezz15J1pcbcjDK0V15rpHetVfya08r76Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@vue/shared": "3.1.5"
+                "@babel/core": "^7.27.4",
+                "@babel/plugin-transform-react-jsx-self": "^7.27.1",
+                "@babel/plugin-transform-react-jsx-source": "^7.27.1",
+                "@rolldown/pluginutils": "1.0.0-beta.11",
+                "@types/babel__core": "^7.20.5",
+                "react-refresh": "^0.17.0"
+            },
+            "engines": {
+                "node": "^14.18.0 || >=16.0.0"
+            },
+            "peerDependencies": {
+                "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0"
             }
         },
             }
         },
-        "node_modules/@vue/shared": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
-            "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==",
-            "dev": true
+        "node_modules/@vitest/coverage-v8": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz",
+            "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@ampproject/remapping": "^2.3.0",
+                "@bcoe/v8-coverage": "^1.0.2",
+                "ast-v8-to-istanbul": "^0.3.3",
+                "debug": "^4.4.1",
+                "istanbul-lib-coverage": "^3.2.2",
+                "istanbul-lib-report": "^3.0.1",
+                "istanbul-lib-source-maps": "^5.0.6",
+                "istanbul-reports": "^3.1.7",
+                "magic-string": "^0.30.17",
+                "magicast": "^0.3.5",
+                "std-env": "^3.9.0",
+                "test-exclude": "^7.0.1",
+                "tinyrainbow": "^2.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            },
+            "peerDependencies": {
+                "@vitest/browser": "3.2.4",
+                "vitest": "3.2.4"
+            },
+            "peerDependenciesMeta": {
+                "@vitest/browser": {
+                    "optional": true
+                }
+            }
         },
         },
-        "node_modules/@webassemblyjs/ast": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
-            "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
+        "node_modules/@vitest/expect": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz",
+            "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@webassemblyjs/helper-numbers": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
+                "@types/chai": "^5.2.2",
+                "@vitest/spy": "3.2.4",
+                "@vitest/utils": "3.2.4",
+                "chai": "^5.2.0",
+                "tinyrainbow": "^2.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
             }
         },
             }
         },
-        "node_modules/@webassemblyjs/floating-point-hex-parser": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
-            "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
-            "dev": true
-        },
-        "node_modules/@webassemblyjs/helper-api-error": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
-            "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
-            "dev": true
-        },
-        "node_modules/@webassemblyjs/helper-buffer": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
-            "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
-            "dev": true
-        },
-        "node_modules/@webassemblyjs/helper-numbers": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
-            "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
+        "node_modules/@vitest/mocker": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz",
+            "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@webassemblyjs/floating-point-hex-parser": "1.11.6",
-                "@webassemblyjs/helper-api-error": "1.11.6",
-                "@xtuc/long": "4.2.2"
-            }
-        },
-        "node_modules/@webassemblyjs/helper-wasm-bytecode": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
-            "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
-            "dev": true
+                "@vitest/spy": "3.2.4",
+                "estree-walker": "^3.0.3",
+                "magic-string": "^0.30.17"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            },
+            "peerDependencies": {
+                "msw": "^2.4.9",
+                "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+            },
+            "peerDependenciesMeta": {
+                "msw": {
+                    "optional": true
+                },
+                "vite": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/@vitest/mocker/node_modules/estree-walker": {
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+            "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/estree": "^1.0.0"
+            }
+        },
+        "node_modules/@vitest/pretty-format": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz",
+            "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "tinyrainbow": "^2.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            }
+        },
+        "node_modules/@vitest/runner": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz",
+            "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@vitest/utils": "3.2.4",
+                "pathe": "^2.0.3",
+                "strip-literal": "^3.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            }
+        },
+        "node_modules/@vitest/snapshot": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz",
+            "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@vitest/pretty-format": "3.2.4",
+                "magic-string": "^0.30.17",
+                "pathe": "^2.0.3"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            }
+        },
+        "node_modules/@vitest/spy": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz",
+            "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "tinyspy": "^4.0.3"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            }
+        },
+        "node_modules/@vitest/utils": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz",
+            "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@vitest/pretty-format": "3.2.4",
+                "loupe": "^3.1.4",
+                "tinyrainbow": "^2.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            }
+        },
+        "node_modules/@vue/reactivity": {
+            "version": "3.1.5",
+            "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz",
+            "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@vue/shared": "3.1.5"
+            }
+        },
+        "node_modules/@vue/shared": {
+            "version": "3.1.5",
+            "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
+            "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/@webassemblyjs/ast": {
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
+            "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@webassemblyjs/helper-numbers": "1.13.2",
+                "@webassemblyjs/helper-wasm-bytecode": "1.13.2"
+            }
+        },
+        "node_modules/@webassemblyjs/floating-point-hex-parser": {
+            "version": "1.13.2",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
+            "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/@webassemblyjs/helper-api-error": {
+            "version": "1.13.2",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
+            "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/@webassemblyjs/helper-buffer": {
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
+            "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/@webassemblyjs/helper-numbers": {
+            "version": "1.13.2",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
+            "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@webassemblyjs/floating-point-hex-parser": "1.13.2",
+                "@webassemblyjs/helper-api-error": "1.13.2",
+                "@xtuc/long": "4.2.2"
+            }
+        },
+        "node_modules/@webassemblyjs/helper-wasm-bytecode": {
+            "version": "1.13.2",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
+            "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@webassemblyjs/helper-wasm-section": {
         },
         "node_modules/@webassemblyjs/helper-wasm-section": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
-            "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
+            "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-buffer": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
-                "@webassemblyjs/wasm-gen": "1.11.6"
+                "@webassemblyjs/ast": "1.14.1",
+                "@webassemblyjs/helper-buffer": "1.14.1",
+                "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+                "@webassemblyjs/wasm-gen": "1.14.1"
             }
         },
         "node_modules/@webassemblyjs/ieee754": {
             }
         },
         "node_modules/@webassemblyjs/ieee754": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
-            "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
+            "version": "1.13.2",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
+            "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@xtuc/ieee754": "^1.2.0"
             }
         },
         "node_modules/@webassemblyjs/leb128": {
             "dependencies": {
                 "@xtuc/ieee754": "^1.2.0"
             }
         },
         "node_modules/@webassemblyjs/leb128": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
-            "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
+            "version": "1.13.2",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
+            "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
                 "@xtuc/long": "4.2.2"
             }
         },
         "node_modules/@webassemblyjs/utf8": {
             "dependencies": {
                 "@xtuc/long": "4.2.2"
             }
         },
         "node_modules/@webassemblyjs/utf8": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
-            "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
-            "dev": true
+            "version": "1.13.2",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
+            "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/@webassemblyjs/wasm-edit": {
         },
         "node_modules/@webassemblyjs/wasm-edit": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
-            "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
+            "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-buffer": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
-                "@webassemblyjs/helper-wasm-section": "1.11.6",
-                "@webassemblyjs/wasm-gen": "1.11.6",
-                "@webassemblyjs/wasm-opt": "1.11.6",
-                "@webassemblyjs/wasm-parser": "1.11.6",
-                "@webassemblyjs/wast-printer": "1.11.6"
+                "@webassemblyjs/ast": "1.14.1",
+                "@webassemblyjs/helper-buffer": "1.14.1",
+                "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+                "@webassemblyjs/helper-wasm-section": "1.14.1",
+                "@webassemblyjs/wasm-gen": "1.14.1",
+                "@webassemblyjs/wasm-opt": "1.14.1",
+                "@webassemblyjs/wasm-parser": "1.14.1",
+                "@webassemblyjs/wast-printer": "1.14.1"
             }
         },
         "node_modules/@webassemblyjs/wasm-gen": {
             }
         },
         "node_modules/@webassemblyjs/wasm-gen": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
-            "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
+            "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
-                "@webassemblyjs/ieee754": "1.11.6",
-                "@webassemblyjs/leb128": "1.11.6",
-                "@webassemblyjs/utf8": "1.11.6"
+                "@webassemblyjs/ast": "1.14.1",
+                "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+                "@webassemblyjs/ieee754": "1.13.2",
+                "@webassemblyjs/leb128": "1.13.2",
+                "@webassemblyjs/utf8": "1.13.2"
             }
         },
         "node_modules/@webassemblyjs/wasm-opt": {
             }
         },
         "node_modules/@webassemblyjs/wasm-opt": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
-            "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
+            "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-buffer": "1.11.6",
-                "@webassemblyjs/wasm-gen": "1.11.6",
-                "@webassemblyjs/wasm-parser": "1.11.6"
+                "@webassemblyjs/ast": "1.14.1",
+                "@webassemblyjs/helper-buffer": "1.14.1",
+                "@webassemblyjs/wasm-gen": "1.14.1",
+                "@webassemblyjs/wasm-parser": "1.14.1"
             }
         },
         "node_modules/@webassemblyjs/wasm-parser": {
             }
         },
         "node_modules/@webassemblyjs/wasm-parser": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
-            "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
+            "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-api-error": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
-                "@webassemblyjs/ieee754": "1.11.6",
-                "@webassemblyjs/leb128": "1.11.6",
-                "@webassemblyjs/utf8": "1.11.6"
+                "@webassemblyjs/ast": "1.14.1",
+                "@webassemblyjs/helper-api-error": "1.13.2",
+                "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+                "@webassemblyjs/ieee754": "1.13.2",
+                "@webassemblyjs/leb128": "1.13.2",
+                "@webassemblyjs/utf8": "1.13.2"
             }
         },
         "node_modules/@webassemblyjs/wast-printer": {
             }
         },
         "node_modules/@webassemblyjs/wast-printer": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
-            "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
+            "version": "1.14.1",
+            "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
+            "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@webassemblyjs/ast": "1.11.6",
+                "@webassemblyjs/ast": "1.14.1",
                 "@xtuc/long": "4.2.2"
             }
         },
                 "@xtuc/long": "4.2.2"
             }
         },
             "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
             "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
             "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
             "dev": true,
+            "license": "MIT",
             "peerDependencies": {
                 "webpack": "4.x.x || 5.x.x",
                 "webpack-cli": "4.x.x"
             "peerDependencies": {
                 "webpack": "4.x.x || 5.x.x",
                 "webpack-cli": "4.x.x"
             "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
             "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
             "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "envinfo": "^7.7.3"
             },
             "dependencies": {
                 "envinfo": "^7.7.3"
             },
             "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
             "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
             "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
             "dev": true,
+            "license": "MIT",
             "peerDependencies": {
                 "webpack-cli": "4.x.x"
             },
             "peerDependencies": {
                 "webpack-cli": "4.x.x"
             },
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
             "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
             "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
-            "dev": true
+            "dev": true,
+            "license": "BSD-3-Clause"
         },
         "node_modules/@xtuc/long": {
             "version": "4.2.2",
             "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
             "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
         },
         "node_modules/@xtuc/long": {
             "version": "4.2.2",
             "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
             "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
-            "dev": true
-        },
-        "node_modules/abab": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
-            "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
-            "deprecated": "Use your platform's native atob() and btoa() methods instead",
-            "dev": true
+            "dev": true,
+            "license": "Apache-2.0"
         },
         "node_modules/accepts": {
             "version": "1.3.8",
             "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
             "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
             "dev": true,
         },
         "node_modules/accepts": {
             "version": "1.3.8",
             "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
             "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "mime-types": "~2.1.34",
                 "negotiator": "0.6.3"
             "dependencies": {
                 "mime-types": "~2.1.34",
                 "negotiator": "0.6.3"
                 "node": ">= 0.6"
             }
         },
                 "node": ">= 0.6"
             }
         },
+        "node_modules/accepts/node_modules/negotiator": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+            "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.6"
+            }
+        },
         "node_modules/acorn": {
         "node_modules/acorn": {
-            "version": "8.10.0",
-            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
-            "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+            "version": "8.15.0",
+            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+            "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "bin": {
                 "acorn": "bin/acorn"
             },
             "bin": {
                 "acorn": "bin/acorn"
             },
                 "node": ">=0.4.0"
             }
         },
                 "node": ">=0.4.0"
             }
         },
-        "node_modules/acorn-globals": {
-            "version": "7.0.1",
-            "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz",
-            "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==",
-            "dev": true,
-            "dependencies": {
-                "acorn": "^8.1.0",
-                "acorn-walk": "^8.0.2"
-            }
-        },
-        "node_modules/acorn-import-assertions": {
-            "version": "1.9.0",
-            "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
-            "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
-            "dev": true,
-            "peerDependencies": {
-                "acorn": "^8"
-            }
-        },
         "node_modules/acorn-jsx": {
             "version": "5.3.2",
             "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
             "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
             "dev": true,
         "node_modules/acorn-jsx": {
             "version": "5.3.2",
             "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
             "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
             "dev": true,
+            "license": "MIT",
             "peerDependencies": {
                 "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
             }
         },
             "peerDependencies": {
                 "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
             }
         },
-        "node_modules/acorn-walk": {
-            "version": "8.3.2",
-            "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
-            "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.4.0"
-            }
-        },
         "node_modules/adjust-sourcemap-loader": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz",
             "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==",
             "dev": true,
         "node_modules/adjust-sourcemap-loader": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz",
             "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "loader-utils": "^2.0.0",
                 "regex-parser": "^2.2.11"
             "dependencies": {
                 "loader-utils": "^2.0.0",
                 "regex-parser": "^2.2.11"
             }
         },
         "node_modules/agent-base": {
             }
         },
         "node_modules/agent-base": {
-            "version": "6.0.2",
-            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-            "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+            "version": "7.1.3",
+            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+            "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "debug": "4"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">= 6.0.0"
+                "node": ">= 14"
             }
         },
         "node_modules/ajv": {
             }
         },
         "node_modules/ajv": {
             "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
             "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
             "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "fast-deep-equal": "^3.1.1",
                 "fast-json-stable-stringify": "^2.0.0",
             "dependencies": {
                 "fast-deep-equal": "^3.1.1",
                 "fast-json-stable-stringify": "^2.0.0",
             "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
             "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
             "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ajv": "^8.0.0"
             },
             "dependencies": {
                 "ajv": "^8.0.0"
             },
             }
         },
         "node_modules/ajv-formats/node_modules/ajv": {
             }
         },
         "node_modules/ajv-formats/node_modules/ajv": {
-            "version": "8.12.0",
-            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
-            "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+            "version": "8.17.1",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+            "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "fast-deep-equal": "^3.1.1",
+                "fast-deep-equal": "^3.1.3",
+                "fast-uri": "^3.0.1",
                 "json-schema-traverse": "^1.0.0",
                 "json-schema-traverse": "^1.0.0",
-                "require-from-string": "^2.0.2",
-                "uri-js": "^4.2.2"
+                "require-from-string": "^2.0.2"
             },
             "funding": {
                 "type": "github",
             },
             "funding": {
                 "type": "github",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
             "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
             "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/ajv-keywords": {
             "version": "3.5.2",
             "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
             "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
             "dev": true,
         },
         "node_modules/ajv-keywords": {
             "version": "3.5.2",
             "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
             "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
             "dev": true,
+            "license": "MIT",
             "peerDependencies": {
                 "ajv": "^6.9.1"
             }
         },
         "node_modules/alpinejs": {
             "peerDependencies": {
                 "ajv": "^6.9.1"
             }
         },
         "node_modules/alpinejs": {
-            "version": "3.13.0",
-            "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.0.tgz",
-            "integrity": "sha512-7FYR1Yz3evIjlJD1mZ3SYWSw+jlOmQGeQ1QiSufSQ6J84XMQFkzxm6OobiZ928SfqhGdoIp2SsABNsS4rXMMJw==",
+            "version": "3.14.9",
+            "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.14.9.tgz",
+            "integrity": "sha512-gqSOhTEyryU9FhviNqiHBHzgjkvtukq9tevew29fTj+ofZtfsYriw4zPirHHOAy9bw8QoL3WGhyk7QqCh5AYlw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@vue/reactivity": "~3.1.1"
             }
         },
             "dependencies": {
                 "@vue/reactivity": "~3.1.1"
             }
         },
-        "node_modules/ansi-escapes": {
-            "version": "4.3.2",
-            "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
-            "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
-            "dev": true,
-            "dependencies": {
-                "type-fest": "^0.21.3"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
-        "node_modules/ansi-escapes/node_modules/type-fest": {
-            "version": "0.21.3",
-            "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
-            "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
-            "dev": true,
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
         "node_modules/ansi-html-community": {
             "version": "0.0.8",
             "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
         "node_modules/ansi-html-community": {
             "version": "0.0.8",
             "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
             "engines": [
                 "node >= 0.8.0"
             ],
             "engines": [
                 "node >= 0.8.0"
             ],
+            "license": "Apache-2.0",
             "bin": {
                 "ansi-html": "bin/ansi-html"
             }
             "bin": {
                 "ansi-html": "bin/ansi-html"
             }
             "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
             "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
             "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             }
         },
         "node_modules/ansi-styles": {
             "engines": {
                 "node": ">=8"
             }
         },
         "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==",
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^1.9.0"
+                "color-convert": "^2.0.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=4"
+                "node": ">=8"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
             }
         },
         "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/any-promise": {
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
             "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "peer": true
         },
         "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==",
             "dev": true,
         },
         "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==",
             "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "normalize-path": "^3.0.0",
                 "picomatch": "^2.0.4"
             "dependencies": {
                 "normalize-path": "^3.0.0",
                 "picomatch": "^2.0.4"
             }
         },
         "node_modules/apng-js": {
             }
         },
         "node_modules/apng-js": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/apng-js/-/apng-js-1.1.1.tgz",
-            "integrity": "sha512-UWaloDssWCE8Bj0wipyNxEXPnMadYS0VAjghCLas5nKGqfiBMNdQJhg8Fawq2+jZ50IOM1feKwjiqPAC/bvKgg=="
+            "version": "1.1.5",
+            "resolved": "https://registry.npmjs.org/apng-js/-/apng-js-1.1.5.tgz",
+            "integrity": "sha512-ENBjy3HAyu7slaOgWRvVtFUdSGFWIHZvz8bGKSEM6/OWQm6NgwFquqY8R7YPgm4vnDISEczhZE2NoLAtKlnUfw==",
+            "license": "MIT"
         },
         "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/arg": {
             "version": "5.0.2",
             "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
             "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "peer": true
         },
         "node_modules/argparse": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
             "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
         },
         "node_modules/argparse": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
             "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-            "dev": true
+            "dev": true,
+            "license": "Python-2.0"
         },
         "node_modules/aria-query": {
         },
         "node_modules/aria-query": {
-            "version": "5.3.0",
-            "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
-            "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+            "version": "5.3.2",
+            "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+            "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "dequal": "^2.0.3"
+            "license": "Apache-2.0",
+            "engines": {
+                "node": ">= 0.4"
             }
         },
         "node_modules/array-buffer-byte-length": {
             }
         },
         "node_modules/array-buffer-byte-length": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
-            "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
+            "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "is-array-buffer": "^3.0.1"
+                "call-bound": "^1.0.3",
+                "is-array-buffer": "^3.0.5"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/array-flatten": {
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/array-flatten": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
-            "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
-            "dev": true
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+            "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/array-includes": {
         },
         "node_modules/array-includes": {
-            "version": "3.1.7",
-            "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz",
-            "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==",
+            "version": "3.1.9",
+            "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
+            "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1",
-                "is-string": "^1.0.7"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.4",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.24.0",
+                "es-object-atoms": "^1.1.1",
+                "get-intrinsic": "^1.3.0",
+                "is-string": "^1.1.1",
+                "math-intrinsics": "^1.1.0"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
             "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
             "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             }
         },
             "engines": {
                 "node": ">=8"
             }
         },
+        "node_modules/array.prototype.findlast": {
+            "version": "1.2.5",
+            "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
+            "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "call-bind": "^1.0.7",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.2",
+                "es-errors": "^1.3.0",
+                "es-object-atoms": "^1.0.0",
+                "es-shim-unscopables": "^1.0.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
         "node_modules/array.prototype.findlastindex": {
         "node_modules/array.prototype.findlastindex": {
-            "version": "1.2.3",
-            "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz",
-            "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==",
+            "version": "1.2.6",
+            "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
+            "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "es-shim-unscopables": "^1.0.0",
-                "get-intrinsic": "^1.2.1"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.4",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.9",
+                "es-errors": "^1.3.0",
+                "es-object-atoms": "^1.1.1",
+                "es-shim-unscopables": "^1.1.0"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/array.prototype.flat": {
             }
         },
         "node_modules/array.prototype.flat": {
-            "version": "1.3.2",
-            "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
-            "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
+            "version": "1.3.3",
+            "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+            "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "es-shim-unscopables": "^1.0.0"
+                "call-bind": "^1.0.8",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.5",
+                "es-shim-unscopables": "^1.0.2"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/array.prototype.flatmap": {
             }
         },
         "node_modules/array.prototype.flatmap": {
-            "version": "1.3.1",
-            "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
-            "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
+            "version": "1.3.3",
+            "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+            "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "es-abstract": "^1.20.4",
-                "es-shim-unscopables": "^1.0.0"
+                "call-bind": "^1.0.8",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.5",
+                "es-shim-unscopables": "^1.0.2"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/array.prototype.tosorted": {
             }
         },
         "node_modules/array.prototype.tosorted": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz",
-            "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==",
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
+            "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "es-abstract": "^1.20.4",
-                "es-shim-unscopables": "^1.0.0",
-                "get-intrinsic": "^1.1.3"
+                "call-bind": "^1.0.7",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.3",
+                "es-errors": "^1.3.0",
+                "es-shim-unscopables": "^1.0.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
             }
         },
         "node_modules/arraybuffer.prototype.slice": {
             }
         },
         "node_modules/arraybuffer.prototype.slice": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz",
-            "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==",
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz",
+            "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "array-buffer-byte-length": "^1.0.0",
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1",
-                "is-array-buffer": "^3.0.2",
-                "is-shared-array-buffer": "^1.0.2"
+                "array-buffer-byte-length": "^1.0.1",
+                "call-bind": "^1.0.8",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.5",
+                "es-errors": "^1.3.0",
+                "get-intrinsic": "^1.2.6",
+                "is-array-buffer": "^3.0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/asn1.js": {
             }
         },
         "node_modules/asn1.js": {
-            "version": "5.4.1",
-            "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
-            "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
+            "version": "4.10.1",
+            "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
+            "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "bn.js": "^4.0.0",
                 "inherits": "^2.0.1",
             "dependencies": {
                 "bn.js": "^4.0.0",
                 "inherits": "^2.0.1",
-                "minimalistic-assert": "^1.0.0",
-                "safer-buffer": "^2.1.0"
+                "minimalistic-assert": "^1.0.0"
             }
         },
         "node_modules/asn1.js/node_modules/bn.js": {
             }
         },
         "node_modules/asn1.js/node_modules/bn.js": {
-            "version": "4.12.0",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-            "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-            "dev": true
+            "version": "4.12.2",
+            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
+            "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/assert": {
         },
         "node_modules/assert": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
-            "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
+            "version": "1.5.1",
+            "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz",
+            "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "object-assign": "^4.1.1",
-                "util": "0.10.3"
+                "object.assign": "^4.1.4",
+                "util": "^0.10.4"
             }
         },
         "node_modules/assert/node_modules/inherits": {
             }
         },
         "node_modules/assert/node_modules/inherits": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
-            "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==",
-            "dev": true
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+            "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
+            "dev": true,
+            "license": "ISC"
         },
         "node_modules/assert/node_modules/util": {
         },
         "node_modules/assert/node_modules/util": {
-            "version": "0.10.3",
-            "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
-            "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==",
+            "version": "0.10.4",
+            "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
+            "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "inherits": "2.0.1"
+                "inherits": "2.0.3"
             }
         },
             }
         },
-        "node_modules/asynciterator.prototype": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz",
-            "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==",
+        "node_modules/assertion-error": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
+            "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-symbols": "^1.0.3"
+            "license": "MIT",
+            "engines": {
+                "node": ">=12"
             }
         },
             }
         },
-        "node_modules/asynckit": {
-            "version": "0.4.0",
-            "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-            "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
-            "dev": true
+        "node_modules/ast-v8-to-istanbul": {
+            "version": "0.3.3",
+            "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.3.tgz",
+            "integrity": "sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@jridgewell/trace-mapping": "^0.3.25",
+                "estree-walker": "^3.0.3",
+                "js-tokens": "^9.0.1"
+            }
         },
         },
-        "node_modules/autoprefixer": {
-            "version": "10.4.15",
-            "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz",
-            "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==",
+        "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": {
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+            "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/estree": "^1.0.0"
+            }
+        },
+        "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": {
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+            "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/async-function": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz",
+            "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/asynckit": {
+            "version": "0.4.0",
+            "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+            "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/autoprefixer": {
+            "version": "10.4.21",
+            "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
+            "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
             "dev": true,
             "funding": [
                 {
             "dev": true,
             "funding": [
                 {
                     "url": "https://github.com/sponsors/ai"
                 }
             ],
                     "url": "https://github.com/sponsors/ai"
                 }
             ],
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserslist": "^4.21.10",
-                "caniuse-lite": "^1.0.30001520",
-                "fraction.js": "^4.2.0",
+                "browserslist": "^4.24.4",
+                "caniuse-lite": "^1.0.30001702",
+                "fraction.js": "^4.3.7",
                 "normalize-range": "^0.1.2",
                 "normalize-range": "^0.1.2",
-                "picocolors": "^1.0.0",
+                "picocolors": "^1.1.1",
                 "postcss-value-parser": "^4.2.0"
             },
             "bin": {
                 "postcss-value-parser": "^4.2.0"
             },
             "bin": {
             "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
             "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
             "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "possible-typed-array-names": "^1.0.0"
             },
             "dependencies": {
                 "possible-typed-array-names": "^1.0.0"
             },
             }
         },
         "node_modules/axios": {
             }
         },
         "node_modules/axios": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
-            "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
+            "version": "1.10.0",
+            "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz",
+            "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "follow-redirects": "^1.15.0",
+                "follow-redirects": "^1.15.6",
                 "form-data": "^4.0.0",
                 "proxy-from-env": "^1.1.0"
             }
         },
                 "form-data": "^4.0.0",
                 "proxy-from-env": "^1.1.0"
             }
         },
-        "node_modules/babel-jest": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
-            "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
-            "dev": true,
-            "dependencies": {
-                "@jest/transform": "^29.7.0",
-                "@types/babel__core": "^7.1.14",
-                "babel-plugin-istanbul": "^6.1.1",
-                "babel-preset-jest": "^29.6.3",
-                "chalk": "^4.0.0",
-                "graceful-fs": "^4.2.9",
-                "slash": "^3.0.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.8.0"
-            }
-        },
-        "node_modules/babel-jest/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-            }
-        },
-        "node_modules/babel-jest/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-            "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
-            }
-        },
-        "node_modules/babel-jest/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-            "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/babel-jest/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/babel-jest/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/babel-jest/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-            "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/babel-loader": {
         "node_modules/babel-loader": {
-            "version": "8.3.0",
-            "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz",
-            "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==",
+            "version": "8.4.1",
+            "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.4.1.tgz",
+            "integrity": "sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "find-cache-dir": "^3.3.1",
             "dependencies": {
                 "find-cache-dir": "^3.3.1",
-                "loader-utils": "^2.0.0",
+                "loader-utils": "^2.0.4",
                 "make-dir": "^3.1.0",
                 "schema-utils": "^2.6.5"
             },
                 "make-dir": "^3.1.0",
                 "schema-utils": "^2.6.5"
             },
                 "webpack": ">=2"
             }
         },
                 "webpack": ">=2"
             }
         },
-        "node_modules/babel-plugin-istanbul": {
-            "version": "6.1.1",
-            "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
-            "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
-            "dev": true,
-            "dependencies": {
-                "@babel/helper-plugin-utils": "^7.0.0",
-                "@istanbuljs/load-nyc-config": "^1.0.0",
-                "@istanbuljs/schema": "^0.1.2",
-                "istanbul-lib-instrument": "^5.0.4",
-                "test-exclude": "^6.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
-            "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/core": "^7.12.3",
-                "@babel/parser": "^7.14.7",
-                "@istanbuljs/schema": "^0.1.2",
-                "istanbul-lib-coverage": "^3.2.0",
-                "semver": "^6.3.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/babel-plugin-jest-hoist": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
-            "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/template": "^7.3.3",
-                "@babel/types": "^7.3.3",
-                "@types/babel__core": "^7.1.14",
-                "@types/babel__traverse": "^7.0.6"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
         "node_modules/babel-plugin-polyfill-corejs2": {
         "node_modules/babel-plugin-polyfill-corejs2": {
-            "version": "0.4.5",
-            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz",
-            "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==",
+            "version": "0.4.13",
+            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz",
+            "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@babel/compat-data": "^7.22.6",
             "dependencies": {
                 "@babel/compat-data": "^7.22.6",
-                "@babel/helper-define-polyfill-provider": "^0.4.2",
+                "@babel/helper-define-polyfill-provider": "^0.6.4",
                 "semver": "^6.3.1"
             },
             "peerDependencies": {
                 "semver": "^6.3.1"
             },
             "peerDependencies": {
             }
         },
         "node_modules/babel-plugin-polyfill-corejs3": {
             }
         },
         "node_modules/babel-plugin-polyfill-corejs3": {
-            "version": "0.8.3",
-            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz",
-            "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==",
+            "version": "0.11.1",
+            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz",
+            "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-define-polyfill-provider": "^0.4.2",
-                "core-js-compat": "^3.31.0"
+                "@babel/helper-define-polyfill-provider": "^0.6.3",
+                "core-js-compat": "^3.40.0"
             },
             "peerDependencies": {
                 "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
             }
         },
         "node_modules/babel-plugin-polyfill-regenerator": {
             },
             "peerDependencies": {
                 "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
             }
         },
         "node_modules/babel-plugin-polyfill-regenerator": {
-            "version": "0.5.2",
-            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz",
-            "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==",
+            "version": "0.6.4",
+            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz",
+            "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/helper-define-polyfill-provider": "^0.4.2"
+                "@babel/helper-define-polyfill-provider": "^0.6.4"
             },
             "peerDependencies": {
                 "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
             }
         },
             },
             "peerDependencies": {
                 "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
             }
         },
-        "node_modules/babel-preset-current-node-syntax": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
-            "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
-            "dev": true,
-            "dependencies": {
-                "@babel/plugin-syntax-async-generators": "^7.8.4",
-                "@babel/plugin-syntax-bigint": "^7.8.3",
-                "@babel/plugin-syntax-class-properties": "^7.8.3",
-                "@babel/plugin-syntax-import-meta": "^7.8.3",
-                "@babel/plugin-syntax-json-strings": "^7.8.3",
-                "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
-                "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
-                "@babel/plugin-syntax-numeric-separator": "^7.8.3",
-                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-                "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
-                "@babel/plugin-syntax-optional-chaining": "^7.8.3",
-                "@babel/plugin-syntax-top-level-await": "^7.8.3"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.0"
-            }
-        },
-        "node_modules/babel-preset-jest": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
-            "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
-            "dev": true,
-            "dependencies": {
-                "babel-plugin-jest-hoist": "^29.6.3",
-                "babel-preset-current-node-syntax": "^1.0.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.0.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/balanced-match": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
             "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/base64-js": {
             "version": "1.5.1",
         },
         "node_modules/base64-js": {
             "version": "1.5.1",
                     "type": "consulting",
                     "url": "https://feross.org/support"
                 }
                     "type": "consulting",
                     "url": "https://feross.org/support"
                 }
-            ]
+            ],
+            "license": "MIT"
         },
         "node_modules/batch": {
             "version": "0.6.1",
             "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
             "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
         },
         "node_modules/batch": {
             "version": "0.6.1",
             "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
             "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/big.js": {
             "version": "5.2.2",
             "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
             "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
             "dev": true,
         },
         "node_modules/big.js": {
             "version": "5.2.2",
             "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
             "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": "*"
             }
         },
         "node_modules/binary-extensions": {
             "engines": {
                 "node": "*"
             }
         },
         "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==",
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+            "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             "engines": {
                 "node": ">=8"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
         "node_modules/bn.js": {
             }
         },
         "node_modules/bn.js": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
-            "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
-            "dev": true
+            "version": "5.2.2",
+            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz",
+            "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/body-parser": {
         },
         "node_modules/body-parser": {
-            "version": "1.20.1",
-            "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
-            "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+            "version": "1.20.3",
+            "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
+            "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "bytes": "3.1.2",
             "dependencies": {
                 "bytes": "3.1.2",
-                "content-type": "~1.0.4",
+                "content-type": "~1.0.5",
                 "debug": "2.6.9",
                 "depd": "2.0.0",
                 "destroy": "1.2.0",
                 "http-errors": "2.0.0",
                 "iconv-lite": "0.4.24",
                 "on-finished": "2.4.1",
                 "debug": "2.6.9",
                 "depd": "2.0.0",
                 "destroy": "1.2.0",
                 "http-errors": "2.0.0",
                 "iconv-lite": "0.4.24",
                 "on-finished": "2.4.1",
-                "qs": "6.11.0",
-                "raw-body": "2.5.1",
+                "qs": "6.13.0",
+                "raw-body": "2.5.2",
                 "type-is": "~1.6.18",
                 "unpipe": "1.0.0"
             },
                 "type-is": "~1.6.18",
                 "unpipe": "1.0.0"
             },
                 "npm": "1.2.8000 || >= 1.4.16"
             }
         },
                 "npm": "1.2.8000 || >= 1.4.16"
             }
         },
-        "node_modules/body-parser/node_modules/bytes": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
-            "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.8"
-            }
-        },
         "node_modules/body-parser/node_modules/debug": {
             "version": "2.6.9",
             "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
             "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
         "node_modules/body-parser/node_modules/debug": {
             "version": "2.6.9",
             "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
             "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ms": "2.0.0"
             }
             "dependencies": {
                 "ms": "2.0.0"
             }
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
             "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
             "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/body-parser/node_modules/qs": {
         },
         "node_modules/body-parser/node_modules/qs": {
-            "version": "6.11.0",
-            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
-            "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+            "version": "6.13.0",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+            "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
             "dev": true,
             "dev": true,
+            "license": "BSD-3-Clause",
             "dependencies": {
             "dependencies": {
-                "side-channel": "^1.0.4"
+                "side-channel": "^1.0.6"
             },
             "engines": {
                 "node": ">=0.6"
             },
             "engines": {
                 "node": ">=0.6"
             }
         },
         "node_modules/bonjour-service": {
             }
         },
         "node_modules/bonjour-service": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz",
-            "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==",
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz",
+            "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "array-flatten": "^2.1.2",
-                "dns-equal": "^1.0.0",
                 "fast-deep-equal": "^3.1.3",
                 "multicast-dns": "^7.2.5"
             }
                 "fast-deep-equal": "^3.1.3",
                 "multicast-dns": "^7.2.5"
             }
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
             "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
             "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
-            "dev": true
+            "dev": true,
+            "license": "ISC"
         },
         "node_modules/bootstrap": {
         },
         "node_modules/bootstrap": {
-            "version": "5.3.1",
-            "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.1.tgz",
-            "integrity": "sha512-jzwza3Yagduci2x0rr9MeFSORjcHpt0lRZukZPZQJT1Dth5qzV7XcgGqYzi39KGAVYR8QEDVoO0ubFKOxzMG+g==",
+            "version": "5.3.7",
+            "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz",
+            "integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==",
             "dev": true,
             "funding": [
                 {
             "dev": true,
             "funding": [
                 {
                     "url": "https://opencollective.com/bootstrap"
                 }
             ],
                     "url": "https://opencollective.com/bootstrap"
                 }
             ],
+            "license": "MIT",
             "peerDependencies": {
                 "@popperjs/core": "^2.11.8"
             }
         },
         "node_modules/brace-expansion": {
             "peerDependencies": {
                 "@popperjs/core": "^2.11.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==",
+            "version": "1.1.12",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+            "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "balanced-match": "^1.0.0",
                 "concat-map": "0.0.1"
             }
         },
         "node_modules/braces": {
             "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==",
+            "version": "3.0.3",
+            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+            "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "fill-range": "^7.0.1"
+                "fill-range": "^7.1.1"
             },
             "engines": {
                 "node": ">=8"
             },
             "engines": {
                 "node": ">=8"
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
             "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
             "version": "1.1.0",
             "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
             "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/browserify-aes": {
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
             "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
             "dev": true,
         },
         "node_modules/browserify-aes": {
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
             "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "buffer-xor": "^1.0.3",
                 "cipher-base": "^1.0.0",
             "dependencies": {
                 "buffer-xor": "^1.0.3",
                 "cipher-base": "^1.0.0",
             "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
             "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
             "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "browserify-aes": "^1.0.4",
                 "browserify-des": "^1.0.0",
             "dependencies": {
                 "browserify-aes": "^1.0.4",
                 "browserify-des": "^1.0.0",
             "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
             "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
             "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "cipher-base": "^1.0.1",
                 "des.js": "^1.0.0",
             "dependencies": {
                 "cipher-base": "^1.0.1",
                 "des.js": "^1.0.0",
             }
         },
         "node_modules/browserify-rsa": {
             }
         },
         "node_modules/browserify-rsa": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
-            "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz",
+            "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "bn.js": "^5.0.0",
-                "randombytes": "^2.0.1"
+                "bn.js": "^5.2.1",
+                "randombytes": "^2.1.0",
+                "safe-buffer": "^5.2.1"
+            },
+            "engines": {
+                "node": ">= 0.10"
             }
         },
         "node_modules/browserify-sign": {
             }
         },
         "node_modules/browserify-sign": {
-            "version": "4.2.1",
-            "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
-            "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
+            "version": "4.2.3",
+            "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz",
+            "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "bn.js": "^5.1.1",
-                "browserify-rsa": "^4.0.1",
+                "bn.js": "^5.2.1",
+                "browserify-rsa": "^4.1.0",
                 "create-hash": "^1.2.0",
                 "create-hmac": "^1.1.7",
                 "create-hash": "^1.2.0",
                 "create-hmac": "^1.1.7",
-                "elliptic": "^6.5.3",
+                "elliptic": "^6.5.5",
+                "hash-base": "~3.0",
                 "inherits": "^2.0.4",
                 "inherits": "^2.0.4",
-                "parse-asn1": "^5.1.5",
-                "readable-stream": "^3.6.0",
-                "safe-buffer": "^5.2.0"
-            }
-        },
-        "node_modules/browserify-sign/node_modules/readable-stream": {
-            "version": "3.6.2",
-            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-            "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
-            "dev": true,
-            "dependencies": {
-                "inherits": "^2.0.3",
-                "string_decoder": "^1.1.1",
-                "util-deprecate": "^1.0.1"
+                "parse-asn1": "^5.1.7",
+                "readable-stream": "^2.3.8",
+                "safe-buffer": "^5.2.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 6"
+                "node": ">= 0.12"
             }
         },
         "node_modules/browserify-zlib": {
             }
         },
         "node_modules/browserify-zlib": {
             "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
             "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
             "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "pako": "~1.0.5"
             }
         },
         "node_modules/browserslist": {
             "dependencies": {
                 "pako": "~1.0.5"
             }
         },
         "node_modules/browserslist": {
-            "version": "4.23.0",
-            "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
-            "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
+            "version": "4.25.0",
+            "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz",
+            "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==",
             "dev": true,
             "funding": [
                 {
             "dev": true,
             "funding": [
                 {
                     "url": "https://github.com/sponsors/ai"
                 }
             ],
                     "url": "https://github.com/sponsors/ai"
                 }
             ],
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "caniuse-lite": "^1.0.30001587",
-                "electron-to-chromium": "^1.4.668",
-                "node-releases": "^2.0.14",
-                "update-browserslist-db": "^1.0.13"
+                "caniuse-lite": "^1.0.30001718",
+                "electron-to-chromium": "^1.5.160",
+                "node-releases": "^2.0.19",
+                "update-browserslist-db": "^1.1.3"
             },
             "bin": {
                 "browserslist": "cli.js"
             },
             "bin": {
                 "browserslist": "cli.js"
                 "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
             }
         },
                 "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
             }
         },
-        "node_modules/bser": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
-            "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
-            "dev": true,
-            "dependencies": {
-                "node-int64": "^0.4.0"
-            }
-        },
         "node_modules/buffer": {
             "version": "4.9.2",
             "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
             "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
             "dev": true,
         "node_modules/buffer": {
             "version": "4.9.2",
             "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
             "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "base64-js": "^1.0.2",
                 "ieee754": "^1.1.4",
             "dependencies": {
                 "base64-js": "^1.0.2",
                 "ieee754": "^1.1.4",
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
             "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
             "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/buffer-xor": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
             "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
         },
         "node_modules/buffer-xor": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
             "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/builtin-status-codes": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
             "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==",
         },
         "node_modules/builtin-status-codes": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
             "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/bytes": {
         },
         "node_modules/bytes": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
-            "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==",
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+            "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.8"
             }
         },
             "engines": {
                 "node": ">= 0.8"
             }
         },
+        "node_modules/cac": {
+            "version": "6.7.14",
+            "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+            "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=8"
+            }
+        },
         "node_modules/call-bind": {
         "node_modules/call-bind": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
-            "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+            "version": "1.0.8",
+            "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
+            "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
+                "call-bind-apply-helpers": "^1.0.0",
                 "es-define-property": "^1.0.0",
                 "es-define-property": "^1.0.0",
-                "es-errors": "^1.3.0",
-                "function-bind": "^1.1.2",
                 "get-intrinsic": "^1.2.4",
                 "get-intrinsic": "^1.2.4",
-                "set-function-length": "^1.2.1"
+                "set-function-length": "^1.2.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/call-bind-apply-helpers": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+            "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+            "license": "MIT",
+            "dependencies": {
+                "es-errors": "^1.3.0",
+                "function-bind": "^1.1.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/call-bound": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+            "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+            "license": "MIT",
+            "dependencies": {
+                "call-bind-apply-helpers": "^1.0.2",
+                "get-intrinsic": "^1.3.0"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
             "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
             "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6"
             }
             "engines": {
                 "node": ">=6"
             }
             "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
             "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
             "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "pascal-case": "^3.1.2",
                 "tslib": "^2.0.3"
             }
         },
             "dependencies": {
                 "pascal-case": "^3.1.2",
                 "tslib": "^2.0.3"
             }
         },
-        "node_modules/camelcase": {
-            "version": "5.3.1",
-            "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-            "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
-            }
-        },
         "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==",
             "dev": true,
         "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==",
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "engines": {
                 "node": ">= 6"
             }
             "engines": {
                 "node": ">= 6"
             }
             "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
             "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
             "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "browserslist": "^4.0.0",
                 "caniuse-lite": "^1.0.0",
             "dependencies": {
                 "browserslist": "^4.0.0",
                 "caniuse-lite": "^1.0.0",
             }
         },
         "node_modules/caniuse-lite": {
             }
         },
         "node_modules/caniuse-lite": {
-            "version": "1.0.30001589",
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001589.tgz",
-            "integrity": "sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==",
+            "version": "1.0.30001724",
+            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz",
+            "integrity": "sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==",
             "dev": true,
             "funding": [
                 {
             "dev": true,
             "funding": [
                 {
                     "type": "github",
                     "url": "https://github.com/sponsors/ai"
                 }
                     "type": "github",
                     "url": "https://github.com/sponsors/ai"
                 }
-            ]
+            ],
+            "license": "CC-BY-4.0"
         },
         },
-        "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==",
+        "node_modules/chai": {
+            "version": "5.2.0",
+            "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
+            "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^3.2.1",
-                "escape-string-regexp": "^1.0.5",
-                "supports-color": "^5.3.0"
+                "assertion-error": "^2.0.1",
+                "check-error": "^2.1.1",
+                "deep-eql": "^5.0.1",
+                "loupe": "^3.1.0",
+                "pathval": "^2.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=4"
+                "node": ">=12"
             }
         },
             }
         },
-        "node_modules/char-regex": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
-            "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+        "node_modules/chalk": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+            "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ansi-styles": "^4.1.0",
+                "supports-color": "^7.1.0"
+            },
             "engines": {
             "engines": {
-                "node": ">=10"
+                "node": ">=8"
             }
         },
         "node_modules/charenc": {
             }
         },
         "node_modules/charenc": {
             "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
             "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
             "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
             "dev": true,
+            "license": "BSD-3-Clause",
             "engines": {
                 "node": "*"
             }
         },
             "engines": {
                 "node": "*"
             }
         },
+        "node_modules/check-error": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz",
+            "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 16"
+            }
+        },
         "node_modules/chokidar": {
         "node_modules/chokidar": {
-            "version": "3.5.3",
-            "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
-            "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+            "version": "3.6.0",
+            "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+            "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
             "dev": true,
             "dev": true,
-            "funding": [
-                {
-                    "type": "individual",
-                    "url": "https://paulmillr.com/funding/"
-                }
-            ],
+            "license": "MIT",
             "dependencies": {
                 "anymatch": "~3.1.2",
                 "braces": "~3.0.2",
             "dependencies": {
                 "anymatch": "~3.1.2",
                 "braces": "~3.0.2",
             "engines": {
                 "node": ">= 8.10.0"
             },
             "engines": {
                 "node": ">= 8.10.0"
             },
+            "funding": {
+                "url": "https://paulmillr.com/funding/"
+            },
             "optionalDependencies": {
                 "fsevents": "~2.3.2"
             }
             "optionalDependencies": {
                 "fsevents": "~2.3.2"
             }
             "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
             "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
             "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
             "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "is-glob": "^4.0.1"
             },
             "dependencies": {
                 "is-glob": "^4.0.1"
             },
             }
         },
         "node_modules/chrome-trace-event": {
             }
         },
         "node_modules/chrome-trace-event": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
-            "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
+            "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.0"
             }
         },
             "engines": {
                 "node": ">=6.0"
             }
         },
-        "node_modules/ci-info": {
-            "version": "3.9.0",
-            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
-            "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
-            "dev": true,
-            "funding": [
-                {
-                    "type": "github",
-                    "url": "https://github.com/sponsors/sibiraj-s"
-                }
-            ],
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/cipher-base": {
         "node_modules/cipher-base": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
-            "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz",
+            "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.0.1"
+                "inherits": "^2.0.4",
+                "safe-buffer": "^5.2.1"
+            },
+            "engines": {
+                "node": ">= 0.10"
             }
         },
             }
         },
-        "node_modules/cjs-module-lexer": {
-            "version": "1.2.3",
-            "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz",
-            "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
-            "dev": true
-        },
         "node_modules/classnames": {
         "node_modules/classnames": {
-            "version": "2.3.2",
-            "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
-            "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
+            "version": "2.5.1",
+            "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
+            "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
+            "license": "MIT"
         },
         "node_modules/clean-css": {
         },
         "node_modules/clean-css": {
-            "version": "5.3.2",
-            "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz",
-            "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==",
+            "version": "5.3.3",
+            "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
+            "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "source-map": "~0.6.0"
             },
             "dependencies": {
                 "source-map": "~0.6.0"
             },
             }
         },
         "node_modules/cli-table3": {
             }
         },
         "node_modules/cli-table3": {
-            "version": "0.6.3",
-            "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
-            "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==",
+            "version": "0.6.5",
+            "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz",
+            "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "string-width": "^4.2.0"
             },
             "dependencies": {
                 "string-width": "^4.2.0"
             },
             "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
             "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
             "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
             "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "string-width": "^4.2.0",
                 "strip-ansi": "^6.0.1",
             "dependencies": {
                 "string-width": "^4.2.0",
                 "strip-ansi": "^6.0.1",
             "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
             "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
             "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "is-plain-object": "^2.0.4",
                 "kind-of": "^6.0.2",
             "dependencies": {
                 "is-plain-object": "^2.0.4",
                 "kind-of": "^6.0.2",
                 "node": ">=6"
             }
         },
                 "node": ">=6"
             }
         },
-        "node_modules/co": {
-            "version": "4.6.0",
-            "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
-            "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
-            "dev": true,
+        "node_modules/clsx": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+            "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "iojs": ">= 1.0.0",
-                "node": ">= 0.12.0"
+                "node": ">=6"
             }
         },
         "node_modules/codemirror": {
             }
         },
         "node_modules/codemirror": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
-            "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
+            "integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
+            "license": "MIT",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/commands": "^6.0.0",
             "dependencies": {
                 "@codemirror/autocomplete": "^6.0.0",
                 "@codemirror/commands": "^6.0.0",
                 "@codemirror/view": "^6.0.0"
             }
         },
                 "@codemirror/view": "^6.0.0"
             }
         },
-        "node_modules/collect-v8-coverage": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
-            "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==",
-            "dev": true
-        },
         "node_modules/collect.js": {
             "version": "4.36.1",
             "resolved": "https://registry.npmjs.org/collect.js/-/collect.js-4.36.1.tgz",
             "integrity": "sha512-jd97xWPKgHn6uvK31V6zcyPd40lUJd7gpYxbN2VOVxGWO4tyvS9Li4EpsFjXepGTo2tYcOTC4a8YsbQXMJ4XUw==",
         "node_modules/collect.js": {
             "version": "4.36.1",
             "resolved": "https://registry.npmjs.org/collect.js/-/collect.js-4.36.1.tgz",
             "integrity": "sha512-jd97xWPKgHn6uvK31V6zcyPd40lUJd7gpYxbN2VOVxGWO4tyvS9Li4EpsFjXepGTo2tYcOTC4a8YsbQXMJ4XUw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/color-convert": {
         },
         "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==",
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "1.1.3"
+                "color-name": "~1.1.4"
+            },
+            "engines": {
+                "node": ">=7.0.0"
             }
         },
         "node_modules/color-name": {
             }
         },
         "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==",
-            "dev": true
+            "version": "1.1.4",
+            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/colord": {
             "version": "2.9.3",
             "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
             "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
         },
         "node_modules/colord": {
             "version": "2.9.3",
             "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
             "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/colorette": {
             "version": "2.0.20",
             "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
             "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
         },
         "node_modules/colorette": {
             "version": "2.0.20",
             "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
             "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/combined-stream": {
             "version": "1.0.8",
             "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
             "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
             "dev": true,
         },
         "node_modules/combined-stream": {
             "version": "1.0.8",
             "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
             "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "delayed-stream": "~1.0.0"
             },
             "dependencies": {
                 "delayed-stream": "~1.0.0"
             },
             "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
             "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
             "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 10"
             }
             "engines": {
                 "node": ">= 10"
             }
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
             "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
             "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/compressible": {
             "version": "2.0.18",
             "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
             "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
             "dev": true,
         },
         "node_modules/compressible": {
             "version": "2.0.18",
             "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
             "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "mime-db": ">= 1.43.0 < 2"
             },
             "dependencies": {
                 "mime-db": ">= 1.43.0 < 2"
             },
             }
         },
         "node_modules/compression": {
             }
         },
         "node_modules/compression": {
-            "version": "1.7.4",
-            "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
-            "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
+            "version": "1.8.0",
+            "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz",
+            "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "accepts": "~1.3.5",
-                "bytes": "3.0.0",
-                "compressible": "~2.0.16",
+                "bytes": "3.1.2",
+                "compressible": "~2.0.18",
                 "debug": "2.6.9",
                 "debug": "2.6.9",
+                "negotiator": "~0.6.4",
                 "on-headers": "~1.0.2",
                 "on-headers": "~1.0.2",
-                "safe-buffer": "5.1.2",
+                "safe-buffer": "5.2.1",
                 "vary": "~1.1.2"
             },
             "engines": {
                 "vary": "~1.1.2"
             },
             "engines": {
             "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
             "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
             "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ms": "2.0.0"
             }
             "dependencies": {
                 "ms": "2.0.0"
             }
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
             "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
             "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-            "dev": true
-        },
-        "node_modules/compression/node_modules/safe-buffer": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/concat": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/concat/-/concat-1.0.3.tgz",
             "integrity": "sha512-f/ZaH1aLe64qHgTILdldbvyfGiGF4uzeo9IuXUloIOLQzFmIPloy9QbZadNsuVv0j5qbKQvQb/H/UYf2UsKTpw==",
             "dev": true,
         },
         "node_modules/concat": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/concat/-/concat-1.0.3.tgz",
             "integrity": "sha512-f/ZaH1aLe64qHgTILdldbvyfGiGF4uzeo9IuXUloIOLQzFmIPloy9QbZadNsuVv0j5qbKQvQb/H/UYf2UsKTpw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "commander": "^2.9.0"
             },
             "dependencies": {
                 "commander": "^2.9.0"
             },
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
             "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
             "version": "0.0.1",
             "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
             "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/concat/node_modules/commander": {
             "version": "2.20.3",
             "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
             "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
         },
         "node_modules/concat/node_modules/commander": {
             "version": "2.20.3",
             "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
             "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/connect-history-api-fallback": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
             "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==",
             "dev": true,
         },
         "node_modules/connect-history-api-fallback": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
             "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.8"
             }
             "engines": {
                 "node": ">=0.8"
             }
             "version": "2.15.3",
             "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
             "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==",
             "version": "2.15.3",
             "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
             "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/console-browserify": {
             "version": "1.2.0",
         },
         "node_modules/console-browserify": {
             "version": "1.2.0",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
             "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
             "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/content-disposition": {
             "version": "0.5.4",
             "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
             "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
             "dev": true,
         },
         "node_modules/content-disposition": {
             "version": "0.5.4",
             "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
             "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "safe-buffer": "5.2.1"
             },
             "dependencies": {
                 "safe-buffer": "5.2.1"
             },
             "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
             "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
             "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.6"
             }
         },
         "node_modules/convert-source-map": {
             "engines": {
                 "node": ">= 0.6"
             }
         },
         "node_modules/convert-source-map": {
-            "version": "1.9.0",
-            "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
-            "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
-            "dev": true
+            "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==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/cookie": {
         },
         "node_modules/cookie": {
-            "version": "0.5.0",
-            "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
-            "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+            "version": "0.7.1",
+            "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
+            "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.6"
             }
             "engines": {
                 "node": ">= 0.6"
             }
             "version": "1.0.6",
             "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
             "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
             "version": "1.0.6",
             "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
             "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/core-js-compat": {
         },
         "node_modules/core-js-compat": {
-            "version": "3.32.1",
-            "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.1.tgz",
-            "integrity": "sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==",
+            "version": "3.43.0",
+            "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.43.0.tgz",
+            "integrity": "sha512-2GML2ZsCc5LR7hZYz4AXmjQw8zuy2T//2QntwdnpuYI7jteT6GVYJL7F6C2C57R7gSYrcqVW3lAALefdbhBLDA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserslist": "^4.21.10"
+                "browserslist": "^4.25.0"
             },
             "funding": {
                 "type": "opencollective",
             },
             "funding": {
                 "type": "opencollective",
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
             "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
             "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/cosmiconfig": {
             "version": "7.1.0",
             "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
             "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
             "dev": true,
         },
         "node_modules/cosmiconfig": {
             "version": "7.1.0",
             "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
             "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/parse-json": "^4.0.0",
                 "import-fresh": "^3.2.1",
             "dependencies": {
                 "@types/parse-json": "^4.0.0",
                 "import-fresh": "^3.2.1",
                 "node": ">=10"
             }
         },
                 "node": ">=10"
             }
         },
+        "node_modules/cosmiconfig/node_modules/yaml": {
+            "version": "1.10.2",
+            "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+            "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+            "dev": true,
+            "license": "ISC",
+            "engines": {
+                "node": ">= 6"
+            }
+        },
         "node_modules/crc-32": {
             "version": "1.2.2",
             "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
             "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
         "node_modules/crc-32": {
             "version": "1.2.2",
             "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
             "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+            "license": "Apache-2.0",
             "bin": {
                 "crc32": "bin/crc32.njs"
             },
             "bin": {
                 "crc32": "bin/crc32.njs"
             },
             "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
             "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
             "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "bn.js": "^4.1.0",
                 "elliptic": "^6.5.3"
             }
         },
         "node_modules/create-ecdh/node_modules/bn.js": {
             "dependencies": {
                 "bn.js": "^4.1.0",
                 "elliptic": "^6.5.3"
             }
         },
         "node_modules/create-ecdh/node_modules/bn.js": {
-            "version": "4.12.0",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-            "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-            "dev": true
+            "version": "4.12.2",
+            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
+            "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/create-hash": {
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
             "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
             "dev": true,
         },
         "node_modules/create-hash": {
             "version": "1.2.0",
             "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
             "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "cipher-base": "^1.0.1",
                 "inherits": "^2.0.1",
             "dependencies": {
                 "cipher-base": "^1.0.1",
                 "inherits": "^2.0.1",
             "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
             "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
             "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "cipher-base": "^1.0.3",
                 "create-hash": "^1.1.0",
             "dependencies": {
                 "cipher-base": "^1.0.3",
                 "create-hash": "^1.1.0",
                 "sha.js": "^2.4.8"
             }
         },
                 "sha.js": "^2.4.8"
             }
         },
-        "node_modules/create-jest": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
-            "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
-            "dev": true,
-            "dependencies": {
-                "@jest/types": "^29.6.3",
-                "chalk": "^4.0.0",
-                "exit": "^0.1.2",
-                "graceful-fs": "^4.2.9",
-                "jest-config": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "prompts": "^2.0.1"
-            },
-            "bin": {
-                "create-jest": "bin/create-jest.js"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
-        "node_modules/create-jest/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-            }
-        },
-        "node_modules/create-jest/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-            "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
-            }
-        },
-        "node_modules/create-jest/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-            "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/create-jest/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/create-jest/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/create-jest/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-            "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/crelt": {
             "version": "1.0.6",
             "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
         "node_modules/crelt": {
             "version": "1.0.6",
             "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
-            "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
+            "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
+            "license": "MIT"
         },
         "node_modules/cross-spawn": {
         },
         "node_modules/cross-spawn": {
-            "version": "7.0.3",
-            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-            "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+            "version": "7.0.6",
+            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+            "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "path-key": "^3.1.0",
                 "shebang-command": "^2.0.0",
             "dependencies": {
                 "path-key": "^3.1.0",
                 "shebang-command": "^2.0.0",
             "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
             "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
             "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
             "dev": true,
+            "license": "BSD-3-Clause",
             "engines": {
                 "node": "*"
             }
         },
         "node_modules/crypto-browserify": {
             "engines": {
                 "node": "*"
             }
         },
         "node_modules/crypto-browserify": {
-            "version": "3.12.0",
-            "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
-            "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+            "version": "3.12.1",
+            "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz",
+            "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserify-cipher": "^1.0.0",
-                "browserify-sign": "^4.0.0",
-                "create-ecdh": "^4.0.0",
-                "create-hash": "^1.1.0",
-                "create-hmac": "^1.1.0",
-                "diffie-hellman": "^5.0.0",
-                "inherits": "^2.0.1",
-                "pbkdf2": "^3.0.3",
-                "public-encrypt": "^4.0.0",
-                "randombytes": "^2.0.0",
-                "randomfill": "^1.0.3"
+                "browserify-cipher": "^1.0.1",
+                "browserify-sign": "^4.2.3",
+                "create-ecdh": "^4.0.4",
+                "create-hash": "^1.2.0",
+                "create-hmac": "^1.1.7",
+                "diffie-hellman": "^5.0.3",
+                "hash-base": "~3.0.4",
+                "inherits": "^2.0.4",
+                "pbkdf2": "^3.1.2",
+                "public-encrypt": "^4.0.3",
+                "randombytes": "^2.1.0",
+                "randomfill": "^1.0.4"
             },
             "engines": {
             },
             "engines": {
-                "node": "*"
+                "node": ">= 0.10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/css-declaration-sorter": {
             }
         },
         "node_modules/css-declaration-sorter": {
             "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz",
             "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz",
             "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==",
             "dev": true,
+            "license": "ISC",
             "engines": {
                 "node": "^10 || ^12 || >=14"
             },
             "engines": {
                 "node": "^10 || ^12 || >=14"
             },
             "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz",
             "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz",
             "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "icss-utils": "^5.1.0",
                 "loader-utils": "^2.0.0",
             "dependencies": {
                 "icss-utils": "^5.1.0",
                 "loader-utils": "^2.0.0",
                 "webpack": "^4.27.0 || ^5.0.0"
             }
         },
                 "webpack": "^4.27.0 || ^5.0.0"
             }
         },
-        "node_modules/css-loader/node_modules/lru-cache": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-            "dev": true,
-            "dependencies": {
-                "yallist": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
         "node_modules/css-loader/node_modules/schema-utils": {
             "version": "3.3.0",
             "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
             "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
             "dev": true,
         "node_modules/css-loader/node_modules/schema-utils": {
             "version": "3.3.0",
             "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
             "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/json-schema": "^7.0.8",
                 "ajv": "^6.12.5",
             "dependencies": {
                 "@types/json-schema": "^7.0.8",
                 "ajv": "^6.12.5",
             }
         },
         "node_modules/css-loader/node_modules/semver": {
             }
         },
         "node_modules/css-loader/node_modules/semver": {
-            "version": "7.5.4",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-            "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+            "version": "7.7.2",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+            "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "lru-cache": "^6.0.0"
-            },
+            "license": "ISC",
             "bin": {
                 "semver": "bin/semver.js"
             },
             "bin": {
                 "semver": "bin/semver.js"
             },
                 "node": ">=10"
             }
         },
                 "node": ">=10"
             }
         },
-        "node_modules/css-loader/node_modules/yallist": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-            "dev": true
-        },
         "node_modules/css-select": {
             "version": "4.3.0",
             "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
             "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
             "dev": true,
         "node_modules/css-select": {
             "version": "4.3.0",
             "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
             "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "boolbase": "^1.0.0",
                 "css-what": "^6.0.1",
             "dependencies": {
                 "boolbase": "^1.0.0",
                 "css-what": "^6.0.1",
             "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
             "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
             "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "domelementtype": "^2.2.0"
             },
             "dependencies": {
                 "domelementtype": "^2.2.0"
             },
             "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
             "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
             "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "mdn-data": "2.0.14",
                 "source-map": "^0.6.1"
             "dependencies": {
                 "mdn-data": "2.0.14",
                 "source-map": "^0.6.1"
                 "node": ">=8.0.0"
             }
         },
                 "node": ">=8.0.0"
             }
         },
-        "node_modules/css-unit-converter": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
-            "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
-        },
         "node_modules/css-what": {
             "version": "6.1.0",
             "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
             "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
             "dev": true,
         "node_modules/css-what": {
             "version": "6.1.0",
             "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
             "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "engines": {
                 "node": ">= 6"
             },
             "engines": {
                 "node": ">= 6"
             },
             "version": "1.5.1",
             "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
             "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
             "version": "1.5.1",
             "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
             "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "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==",
             "dev": true,
         },
         "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==",
             "dev": true,
+            "license": "MIT",
             "bin": {
                 "cssesc": "bin/cssesc"
             },
             "bin": {
                 "cssesc": "bin/cssesc"
             },
             "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz",
             "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz",
             "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "cssnano-preset-default": "^5.2.14",
                 "lilconfig": "^2.0.3",
             "dependencies": {
                 "cssnano-preset-default": "^5.2.14",
                 "lilconfig": "^2.0.3",
             "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz",
             "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz",
             "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "css-declaration-sorter": "^6.3.1",
                 "cssnano-utils": "^3.1.0",
             "dependencies": {
                 "css-declaration-sorter": "^6.3.1",
                 "cssnano-utils": "^3.1.0",
             "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
             "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
             "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": "^10 || ^12 || >=14.0"
             },
             "engines": {
                 "node": "^10 || ^12 || >=14.0"
             },
                 "postcss": "^8.2.15"
             }
         },
                 "postcss": "^8.2.15"
             }
         },
+        "node_modules/cssnano/node_modules/yaml": {
+            "version": "1.10.2",
+            "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+            "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+            "dev": true,
+            "license": "ISC",
+            "engines": {
+                "node": ">= 6"
+            }
+        },
         "node_modules/csso": {
             "version": "4.2.0",
             "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
             "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
             "dev": true,
         "node_modules/csso": {
             "version": "4.2.0",
             "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
             "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "css-tree": "^1.1.2"
             },
             "dependencies": {
                 "css-tree": "^1.1.2"
             },
                 "node": ">=8.0.0"
             }
         },
                 "node": ">=8.0.0"
             }
         },
-        "node_modules/cssom": {
-            "version": "0.5.0",
-            "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
-            "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==",
-            "dev": true
-        },
         "node_modules/cssstyle": {
         "node_modules/cssstyle": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
-            "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
+            "version": "4.5.0",
+            "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.5.0.tgz",
+            "integrity": "sha512-/7gw8TGrvH/0g564EnhgFZogTMVe+lifpB7LWU+PEsiq5o83TUXR3fDbzTRXOJhoJwck5IS9ez3Em5LNMMO2aw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "cssom": "~0.3.6"
+                "@asamuzakjp/css-color": "^3.2.0",
+                "rrweb-cssom": "^0.8.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/cssstyle/node_modules/cssom": {
-            "version": "0.3.8",
-            "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
-            "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
-            "dev": true
-        },
         "node_modules/csstype": {
         "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=="
+            "version": "3.1.3",
+            "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+            "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+            "license": "MIT"
         },
         "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==",
         },
         "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==",
+            "license": "ISC",
             "dependencies": {
                 "internmap": "1 - 2"
             },
             "dependencies": {
                 "internmap": "1 - 2"
             },
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
             "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
             "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+            "license": "ISC",
             "engines": {
                 "node": ">=12"
             }
             "engines": {
                 "node": ">=12"
             }
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
             "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
             "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
+            "license": "ISC",
             "engines": {
                 "node": ">=12"
             }
             "engines": {
                 "node": ">=12"
             }
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
             "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
             "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
+            "license": "ISC",
             "dependencies": {
                 "d3-dispatch": "1 - 3",
                 "d3-selection": "3"
             "dependencies": {
                 "d3-dispatch": "1 - 3",
                 "d3-selection": "3"
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
             "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
             "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+            "license": "BSD-3-Clause",
             "engines": {
                 "node": ">=12"
             }
             "engines": {
                 "node": ">=12"
             }
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
             "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
             "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+            "license": "ISC",
             "engines": {
                 "node": ">=12"
             }
             "engines": {
                 "node": ">=12"
             }
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
             "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
             "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+            "license": "ISC",
             "dependencies": {
                 "d3-color": "1 - 3"
             },
             "dependencies": {
                 "d3-color": "1 - 3"
             },
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
             "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
             "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+            "license": "ISC",
             "engines": {
                 "node": ">=12"
             }
             "engines": {
                 "node": ">=12"
             }
             "version": "4.0.2",
             "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
             "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
             "version": "4.0.2",
             "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
             "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+            "license": "ISC",
             "dependencies": {
                 "d3-array": "2.10.0 - 3",
                 "d3-format": "1 - 3",
             "dependencies": {
                 "d3-array": "2.10.0 - 3",
                 "d3-format": "1 - 3",
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
             "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
             "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
+            "license": "ISC",
             "engines": {
                 "node": ">=12"
             }
             "engines": {
                 "node": ">=12"
             }
             "version": "3.2.0",
             "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
             "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
             "version": "3.2.0",
             "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
             "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+            "license": "ISC",
             "dependencies": {
                 "d3-path": "^3.1.0"
             },
             "dependencies": {
                 "d3-path": "^3.1.0"
             },
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
             "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
             "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+            "license": "ISC",
             "dependencies": {
                 "d3-array": "2 - 3"
             },
             "dependencies": {
                 "d3-array": "2 - 3"
             },
             "version": "4.1.0",
             "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
             "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
             "version": "4.1.0",
             "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
             "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+            "license": "ISC",
             "dependencies": {
                 "d3-time": "1 - 3"
             },
             "dependencies": {
                 "d3-time": "1 - 3"
             },
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
             "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
             "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+            "license": "ISC",
             "engines": {
                 "node": ">=12"
             }
         },
         "node_modules/data-urls": {
             "engines": {
                 "node": ">=12"
             }
         },
         "node_modules/data-urls": {
-            "version": "3.0.2",
-            "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
-            "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
+            "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "abab": "^2.0.6",
-                "whatwg-mimetype": "^3.0.0",
-                "whatwg-url": "^11.0.0"
+                "whatwg-mimetype": "^4.0.0",
+                "whatwg-url": "^14.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
             }
         },
-        "node_modules/debug": {
-            "version": "4.3.4",
-            "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-            "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+        "node_modules/data-view-buffer": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
+            "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ms": "2.1.2"
+                "call-bound": "^1.0.3",
+                "es-errors": "^1.3.0",
+                "is-data-view": "^1.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=6.0"
+                "node": ">= 0.4"
             },
             },
-            "peerDependenciesMeta": {
-                "supports-color": {
-                    "optional": true
-                }
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/decimal.js": {
-            "version": "10.4.3",
-            "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
-            "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
-            "dev": 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/dedent": {
-            "version": "1.5.1",
-            "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz",
-            "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==",
+        "node_modules/data-view-byte-length": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz",
+            "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==",
             "dev": true,
             "dev": true,
-            "peerDependencies": {
-                "babel-plugin-macros": "^3.1.0"
+            "license": "MIT",
+            "dependencies": {
+                "call-bound": "^1.0.3",
+                "es-errors": "^1.3.0",
+                "is-data-view": "^1.0.2"
             },
             },
-            "peerDependenciesMeta": {
-                "babel-plugin-macros": {
-                    "optional": true
-                }
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/inspect-js"
             }
         },
             }
         },
-        "node_modules/deep-equal": {
-            "version": "2.2.3",
-            "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
-            "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
+        "node_modules/data-view-byte-offset": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz",
+            "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "array-buffer-byte-length": "^1.0.0",
-                "call-bind": "^1.0.5",
-                "es-get-iterator": "^1.1.3",
-                "get-intrinsic": "^1.2.2",
-                "is-arguments": "^1.1.1",
-                "is-array-buffer": "^3.0.2",
-                "is-date-object": "^1.0.5",
-                "is-regex": "^1.1.4",
-                "is-shared-array-buffer": "^1.0.2",
-                "isarray": "^2.0.5",
-                "object-is": "^1.1.5",
-                "object-keys": "^1.1.1",
-                "object.assign": "^4.1.4",
-                "regexp.prototype.flags": "^1.5.1",
-                "side-channel": "^1.0.4",
-                "which-boxed-primitive": "^1.0.2",
-                "which-collection": "^1.0.1",
-                "which-typed-array": "^1.1.13"
+                "call-bound": "^1.0.2",
+                "es-errors": "^1.3.0",
+                "is-data-view": "^1.0.1"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/deep-equal/node_modules/isarray": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-            "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-            "dev": true
+        "node_modules/debug": {
+            "version": "4.4.1",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
+            "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "ms": "^2.1.3"
+            },
+            "engines": {
+                "node": ">=6.0"
+            },
+            "peerDependenciesMeta": {
+                "supports-color": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/decimal.js": {
+            "version": "10.5.0",
+            "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz",
+            "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "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==",
+            "license": "MIT"
+        },
+        "node_modules/deep-eql": {
+            "version": "5.0.2",
+            "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz",
+            "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=6"
+            }
         },
         "node_modules/deep-is": {
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
             "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
         },
         "node_modules/deep-is": {
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
             "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/deepmerge": {
             "version": "2.2.1",
             "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
             "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==",
         },
         "node_modules/deepmerge": {
             "version": "2.2.1",
             "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
             "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==",
+            "license": "MIT",
             "engines": {
                 "node": ">=0.10.0"
             }
             "engines": {
                 "node": ">=0.10.0"
             }
             "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
             "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
             "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "execa": "^5.0.0"
             },
             "dependencies": {
                 "execa": "^5.0.0"
             },
             "version": "1.1.4",
             "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
             "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
             "version": "1.1.4",
             "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
             "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "es-define-property": "^1.0.0",
                 "es-errors": "^1.3.0",
             "dependencies": {
                 "es-define-property": "^1.0.0",
                 "es-errors": "^1.3.0",
             "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
             "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
             "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             }
             "engines": {
                 "node": ">=8"
             }
             "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
             "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
             "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "define-data-property": "^1.0.1",
                 "has-property-descriptors": "^1.0.0",
             "dependencies": {
                 "define-data-property": "^1.0.1",
                 "has-property-descriptors": "^1.0.0",
             "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
             "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
             "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.4.0"
             }
             "engines": {
                 "node": ">=0.4.0"
             }
             "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
             "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
             "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.8"
             }
             "engines": {
                 "node": ">= 0.8"
             }
             "version": "2.0.3",
             "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
             "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
             "version": "2.0.3",
             "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
             "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+            "license": "MIT",
             "engines": {
                 "node": ">=6"
             }
             "engines": {
                 "node": ">=6"
             }
             "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
             "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
             "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "inherits": "^2.0.1",
                 "minimalistic-assert": "^1.0.0"
             "dependencies": {
                 "inherits": "^2.0.1",
                 "minimalistic-assert": "^1.0.0"
             "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
             "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
             "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.8",
                 "npm": "1.2.8000 || >= 1.4.16"
             }
         },
             "engines": {
                 "node": ">= 0.8",
                 "npm": "1.2.8000 || >= 1.4.16"
             }
         },
-        "node_modules/detect-newline": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
-            "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+        "node_modules/detect-libc": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+            "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
+            "optional": true,
+            "bin": {
+                "detect-libc": "bin/detect-libc.js"
+            },
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=0.10"
             }
         },
         "node_modules/detect-node": {
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
             "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
             }
         },
         "node_modules/detect-node": {
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
             "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "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/didyoumean": {
             "version": "1.2.2",
             "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
             "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
-            "dev": true
-        },
-        "node_modules/diff-sequences": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
-            "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
+            "license": "Apache-2.0",
+            "peer": true
         },
         "node_modules/diffie-hellman": {
             "version": "5.0.3",
             "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
             "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
             "dev": true,
         },
         "node_modules/diffie-hellman": {
             "version": "5.0.3",
             "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
             "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "bn.js": "^4.1.0",
                 "miller-rabin": "^4.0.0",
             "dependencies": {
                 "bn.js": "^4.1.0",
                 "miller-rabin": "^4.0.0",
             }
         },
         "node_modules/diffie-hellman/node_modules/bn.js": {
             }
         },
         "node_modules/diffie-hellman/node_modules/bn.js": {
-            "version": "4.12.0",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-            "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-            "dev": true
+            "version": "4.12.2",
+            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
+            "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/dir-glob": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
             "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
             "dev": true,
         },
         "node_modules/dir-glob": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
             "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "path-type": "^4.0.0"
             },
             "dependencies": {
                 "path-type": "^4.0.0"
             },
             "version": "1.1.3",
             "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
             "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
             "version": "1.1.3",
             "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
             "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
-            "dev": true
-        },
-        "node_modules/dns-equal": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
-            "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "peer": true
         },
         "node_modules/dns-packet": {
             "version": "5.6.1",
             "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz",
             "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==",
             "dev": true,
         },
         "node_modules/dns-packet": {
             "version": "5.6.1",
             "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz",
             "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@leichtgewicht/ip-codec": "^2.0.1"
             },
             "dependencies": {
                 "@leichtgewicht/ip-codec": "^2.0.1"
             },
                 "node": ">=6"
             }
         },
                 "node": ">=6"
             }
         },
-        "node_modules/doctrine": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-            "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
-            "dev": true,
-            "dependencies": {
-                "esutils": "^2.0.2"
-            },
-            "engines": {
-                "node": ">=6.0.0"
-            }
-        },
         "node_modules/dom-accessibility-api": {
             "version": "0.6.3",
             "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
             "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
         "node_modules/dom-accessibility-api": {
             "version": "0.6.3",
             "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
             "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/dom-helpers": {
             "version": "5.2.1",
             "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
             "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
         },
         "node_modules/dom-helpers": {
             "version": "5.2.1",
             "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
             "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+            "license": "MIT",
             "dependencies": {
                 "@babel/runtime": "^7.8.7",
                 "csstype": "^3.0.2"
             "dependencies": {
                 "@babel/runtime": "^7.8.7",
                 "csstype": "^3.0.2"
             "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
             "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
             "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "domelementtype": "^2.0.1",
                 "domhandler": "^4.2.0",
             "dependencies": {
                 "domelementtype": "^2.0.1",
                 "domhandler": "^4.2.0",
             "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
             "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
             "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "domelementtype": "^2.2.0"
             },
             "dependencies": {
                 "domelementtype": "^2.2.0"
             },
             "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
             "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
             "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.4",
                 "npm": ">=1.2"
             "engines": {
                 "node": ">=0.4",
                 "npm": ">=1.2"
                     "type": "github",
                     "url": "https://github.com/sponsors/fb55"
                 }
                     "type": "github",
                     "url": "https://github.com/sponsors/fb55"
                 }
-            ]
-        },
-        "node_modules/domexception": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
-            "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
-            "deprecated": "Use your platform's native DOMException instead",
-            "dev": true,
-            "dependencies": {
-                "webidl-conversions": "^7.0.0"
-            },
-            "engines": {
-                "node": ">=12"
-            }
+            ],
+            "license": "BSD-2-Clause"
         },
         "node_modules/domhandler": {
             "version": "3.3.0",
             "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
             "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
             "dev": true,
         },
         "node_modules/domhandler": {
             "version": "3.3.0",
             "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
             "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "domelementtype": "^2.0.1"
             },
             "dependencies": {
                 "domelementtype": "^2.0.1"
             },
             "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
             "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
             "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "dom-serializer": "^1.0.1",
                 "domelementtype": "^2.2.0",
             "dependencies": {
                 "dom-serializer": "^1.0.1",
                 "domelementtype": "^2.2.0",
             "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
             "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
             "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "domelementtype": "^2.2.0"
             },
             "dependencies": {
                 "domelementtype": "^2.2.0"
             },
             "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
             "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
             "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "no-case": "^3.0.4",
                 "tslib": "^2.0.3"
             "dependencies": {
                 "no-case": "^3.0.4",
                 "tslib": "^2.0.3"
             "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
             "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
             "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "engines": {
                 "node": ">=10"
             }
             "engines": {
                 "node": ">=10"
             }
             "version": "5.1.0",
             "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
             "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
             "version": "5.1.0",
             "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
             "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
-            "dev": true
+            "dev": true,
+            "license": "BSD-2-Clause"
+        },
+        "node_modules/dunder-proto": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+            "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+            "license": "MIT",
+            "dependencies": {
+                "call-bind-apply-helpers": "^1.0.1",
+                "es-errors": "^1.3.0",
+                "gopd": "^1.2.0"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/eastasianwidth": {
+            "version": "0.2.0",
+            "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+            "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/ee-first": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
             "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
         },
         "node_modules/ee-first": {
             "version": "1.1.1",
             "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
             "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/electron-to-chromium": {
         },
         "node_modules/electron-to-chromium": {
-            "version": "1.4.680",
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.680.tgz",
-            "integrity": "sha512-4nToZ5jlPO14W82NkF32wyjhYqQByVaDmLy4J2/tYcAbJfgO2TKJC780Az1V13gzq4l73CJ0yuyalpXvxXXD9A==",
-            "dev": true
+            "version": "1.5.171",
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.171.tgz",
+            "integrity": "sha512-scWpzXEJEMrGJa4Y6m/tVotb0WuvNmasv3wWVzUAeCgKU0ToFOhUW6Z+xWnRQANMYGxN4ngJXIThgBJOqzVPCQ==",
+            "dev": true,
+            "license": "ISC"
         },
         "node_modules/elliptic": {
         },
         "node_modules/elliptic": {
-            "version": "6.5.4",
-            "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
-            "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+            "version": "6.6.1",
+            "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
+            "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "bn.js": "^4.11.9",
                 "brorand": "^1.1.0",
             "dependencies": {
                 "bn.js": "^4.11.9",
                 "brorand": "^1.1.0",
             }
         },
         "node_modules/elliptic/node_modules/bn.js": {
             }
         },
         "node_modules/elliptic/node_modules/bn.js": {
-            "version": "4.12.0",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-            "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-            "dev": true
-        },
-        "node_modules/emittery": {
-            "version": "0.13.1",
-            "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
-            "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
+            "version": "4.12.2",
+            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
+            "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=12"
-            },
-            "funding": {
-                "url": "https://github.com/sindresorhus/emittery?sponsor=1"
-            }
+            "license": "MIT"
         },
         "node_modules/emoji-regex": {
             "version": "8.0.0",
             "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
             "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
         },
         "node_modules/emoji-regex": {
             "version": "8.0.0",
             "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
             "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/emojis-list": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
             "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
             "dev": true,
         },
         "node_modules/emojis-list": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
             "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 4"
             }
         },
         "node_modules/encodeurl": {
             "engines": {
                 "node": ">= 4"
             }
         },
         "node_modules/encodeurl": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-            "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+            "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.8"
             }
         },
         "node_modules/enhanced-resolve": {
             "engines": {
                 "node": ">= 0.8"
             }
         },
         "node_modules/enhanced-resolve": {
-            "version": "5.15.0",
-            "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
-            "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
+            "version": "5.18.1",
+            "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
+            "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "graceful-fs": "^4.2.4",
                 "tapable": "^2.2.0"
             "dependencies": {
                 "graceful-fs": "^4.2.4",
                 "tapable": "^2.2.0"
             "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
             "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
             "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "funding": {
                 "url": "https://github.com/fb55/entities?sponsor=1"
             }
         },
         "node_modules/envinfo": {
             "funding": {
                 "url": "https://github.com/fb55/entities?sponsor=1"
             }
         },
         "node_modules/envinfo": {
-            "version": "7.10.0",
-            "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz",
-            "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==",
+            "version": "7.14.0",
+            "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz",
+            "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "bin": {
                 "envinfo": "dist/cli.js"
             },
             "bin": {
                 "envinfo": "dist/cli.js"
             },
             "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
             "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
             "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "is-arrayish": "^0.2.1"
             }
         },
         "node_modules/es-abstract": {
             "dependencies": {
                 "is-arrayish": "^0.2.1"
             }
         },
         "node_modules/es-abstract": {
-            "version": "1.22.1",
-            "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz",
-            "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==",
-            "dev": true,
-            "dependencies": {
-                "array-buffer-byte-length": "^1.0.0",
-                "arraybuffer.prototype.slice": "^1.0.1",
-                "available-typed-arrays": "^1.0.5",
-                "call-bind": "^1.0.2",
-                "es-set-tostringtag": "^2.0.1",
-                "es-to-primitive": "^1.2.1",
-                "function.prototype.name": "^1.1.5",
-                "get-intrinsic": "^1.2.1",
-                "get-symbol-description": "^1.0.0",
-                "globalthis": "^1.0.3",
-                "gopd": "^1.0.1",
-                "has": "^1.0.3",
-                "has-property-descriptors": "^1.0.0",
-                "has-proto": "^1.0.1",
-                "has-symbols": "^1.0.3",
-                "internal-slot": "^1.0.5",
-                "is-array-buffer": "^3.0.2",
+            "version": "1.24.0",
+            "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz",
+            "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "array-buffer-byte-length": "^1.0.2",
+                "arraybuffer.prototype.slice": "^1.0.4",
+                "available-typed-arrays": "^1.0.7",
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.4",
+                "data-view-buffer": "^1.0.2",
+                "data-view-byte-length": "^1.0.2",
+                "data-view-byte-offset": "^1.0.1",
+                "es-define-property": "^1.0.1",
+                "es-errors": "^1.3.0",
+                "es-object-atoms": "^1.1.1",
+                "es-set-tostringtag": "^2.1.0",
+                "es-to-primitive": "^1.3.0",
+                "function.prototype.name": "^1.1.8",
+                "get-intrinsic": "^1.3.0",
+                "get-proto": "^1.0.1",
+                "get-symbol-description": "^1.1.0",
+                "globalthis": "^1.0.4",
+                "gopd": "^1.2.0",
+                "has-property-descriptors": "^1.0.2",
+                "has-proto": "^1.2.0",
+                "has-symbols": "^1.1.0",
+                "hasown": "^2.0.2",
+                "internal-slot": "^1.1.0",
+                "is-array-buffer": "^3.0.5",
                 "is-callable": "^1.2.7",
                 "is-callable": "^1.2.7",
-                "is-negative-zero": "^2.0.2",
-                "is-regex": "^1.1.4",
-                "is-shared-array-buffer": "^1.0.2",
-                "is-string": "^1.0.7",
-                "is-typed-array": "^1.1.10",
-                "is-weakref": "^1.0.2",
-                "object-inspect": "^1.12.3",
+                "is-data-view": "^1.0.2",
+                "is-negative-zero": "^2.0.3",
+                "is-regex": "^1.2.1",
+                "is-set": "^2.0.3",
+                "is-shared-array-buffer": "^1.0.4",
+                "is-string": "^1.1.1",
+                "is-typed-array": "^1.1.15",
+                "is-weakref": "^1.1.1",
+                "math-intrinsics": "^1.1.0",
+                "object-inspect": "^1.13.4",
                 "object-keys": "^1.1.1",
                 "object-keys": "^1.1.1",
-                "object.assign": "^4.1.4",
-                "regexp.prototype.flags": "^1.5.0",
-                "safe-array-concat": "^1.0.0",
-                "safe-regex-test": "^1.0.0",
-                "string.prototype.trim": "^1.2.7",
-                "string.prototype.trimend": "^1.0.6",
-                "string.prototype.trimstart": "^1.0.6",
-                "typed-array-buffer": "^1.0.0",
-                "typed-array-byte-length": "^1.0.0",
-                "typed-array-byte-offset": "^1.0.0",
-                "typed-array-length": "^1.0.4",
-                "unbox-primitive": "^1.0.2",
-                "which-typed-array": "^1.1.10"
+                "object.assign": "^4.1.7",
+                "own-keys": "^1.0.1",
+                "regexp.prototype.flags": "^1.5.4",
+                "safe-array-concat": "^1.1.3",
+                "safe-push-apply": "^1.0.0",
+                "safe-regex-test": "^1.1.0",
+                "set-proto": "^1.0.0",
+                "stop-iteration-iterator": "^1.1.0",
+                "string.prototype.trim": "^1.2.10",
+                "string.prototype.trimend": "^1.0.9",
+                "string.prototype.trimstart": "^1.0.8",
+                "typed-array-buffer": "^1.0.3",
+                "typed-array-byte-length": "^1.0.3",
+                "typed-array-byte-offset": "^1.0.4",
+                "typed-array-length": "^1.0.7",
+                "unbox-primitive": "^1.1.0",
+                "which-typed-array": "^1.1.19"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/es-define-property": {
             }
         },
         "node_modules/es-define-property": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
-            "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
-            "dependencies": {
-                "get-intrinsic": "^1.2.4"
-            },
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+            "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.4"
             }
             "engines": {
                 "node": ">= 0.4"
             }
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
             "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
             "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.4"
             }
         },
             "engines": {
                 "node": ">= 0.4"
             }
         },
-        "node_modules/es-get-iterator": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
-            "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
+        "node_modules/es-iterator-helpers": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz",
+            "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.1.3",
-                "has-symbols": "^1.0.3",
-                "is-arguments": "^1.1.1",
-                "is-map": "^2.0.2",
-                "is-set": "^2.0.2",
-                "is-string": "^1.0.7",
-                "isarray": "^2.0.5",
-                "stop-iteration-iterator": "^1.0.0"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.3",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.6",
+                "es-errors": "^1.3.0",
+                "es-set-tostringtag": "^2.0.3",
+                "function-bind": "^1.1.2",
+                "get-intrinsic": "^1.2.6",
+                "globalthis": "^1.0.4",
+                "gopd": "^1.2.0",
+                "has-property-descriptors": "^1.0.2",
+                "has-proto": "^1.2.0",
+                "has-symbols": "^1.1.0",
+                "internal-slot": "^1.1.0",
+                "iterator.prototype": "^1.1.4",
+                "safe-array-concat": "^1.1.3"
             },
             },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
+            "engines": {
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/es-get-iterator/node_modules/isarray": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-            "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-            "dev": true
+        "node_modules/es-module-lexer": {
+            "version": "1.7.0",
+            "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
+            "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/es-iterator-helpers": {
-            "version": "1.0.14",
-            "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz",
-            "integrity": "sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw==",
-            "dev": true,
-            "dependencies": {
-                "asynciterator.prototype": "^1.0.0",
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "es-set-tostringtag": "^2.0.1",
-                "function-bind": "^1.1.1",
-                "get-intrinsic": "^1.2.1",
-                "globalthis": "^1.0.3",
-                "has-property-descriptors": "^1.0.0",
-                "has-proto": "^1.0.1",
-                "has-symbols": "^1.0.3",
-                "internal-slot": "^1.0.5",
-                "iterator.prototype": "^1.1.0",
-                "safe-array-concat": "^1.0.0"
+        "node_modules/es-object-atoms": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+            "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+            "license": "MIT",
+            "dependencies": {
+                "es-errors": "^1.3.0"
+            },
+            "engines": {
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/es-module-lexer": {
-            "version": "1.3.0",
-            "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
-            "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==",
-            "dev": true
-        },
         "node_modules/es-set-tostringtag": {
         "node_modules/es-set-tostringtag": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
-            "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+            "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "get-intrinsic": "^1.1.3",
-                "has": "^1.0.3",
-                "has-tostringtag": "^1.0.0"
+                "es-errors": "^1.3.0",
+                "get-intrinsic": "^1.2.6",
+                "has-tostringtag": "^1.0.2",
+                "hasown": "^2.0.2"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/es-shim-unscopables": {
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/es-shim-unscopables": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
-            "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
+            "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has": "^1.0.3"
+                "hasown": "^2.0.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
             }
         },
         "node_modules/es-to-primitive": {
             }
         },
         "node_modules/es-to-primitive": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
-            "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz",
+            "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "is-callable": "^1.1.4",
-                "is-date-object": "^1.0.1",
-                "is-symbol": "^1.0.2"
+                "is-callable": "^1.2.7",
+                "is-date-object": "^1.0.5",
+                "is-symbol": "^1.0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
+        "node_modules/esbuild": {
+            "version": "0.25.5",
+            "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
+            "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
+            "dev": true,
+            "hasInstallScript": true,
+            "license": "MIT",
+            "bin": {
+                "esbuild": "bin/esbuild"
+            },
+            "engines": {
+                "node": ">=18"
+            },
+            "optionalDependencies": {
+                "@esbuild/aix-ppc64": "0.25.5",
+                "@esbuild/android-arm": "0.25.5",
+                "@esbuild/android-arm64": "0.25.5",
+                "@esbuild/android-x64": "0.25.5",
+                "@esbuild/darwin-arm64": "0.25.5",
+                "@esbuild/darwin-x64": "0.25.5",
+                "@esbuild/freebsd-arm64": "0.25.5",
+                "@esbuild/freebsd-x64": "0.25.5",
+                "@esbuild/linux-arm": "0.25.5",
+                "@esbuild/linux-arm64": "0.25.5",
+                "@esbuild/linux-ia32": "0.25.5",
+                "@esbuild/linux-loong64": "0.25.5",
+                "@esbuild/linux-mips64el": "0.25.5",
+                "@esbuild/linux-ppc64": "0.25.5",
+                "@esbuild/linux-riscv64": "0.25.5",
+                "@esbuild/linux-s390x": "0.25.5",
+                "@esbuild/linux-x64": "0.25.5",
+                "@esbuild/netbsd-arm64": "0.25.5",
+                "@esbuild/netbsd-x64": "0.25.5",
+                "@esbuild/openbsd-arm64": "0.25.5",
+                "@esbuild/openbsd-x64": "0.25.5",
+                "@esbuild/sunos-x64": "0.25.5",
+                "@esbuild/win32-arm64": "0.25.5",
+                "@esbuild/win32-ia32": "0.25.5",
+                "@esbuild/win32-x64": "0.25.5"
+            }
+        },
         "node_modules/escalade": {
         "node_modules/escalade": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-            "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+            "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6"
             }
             "engines": {
                 "node": ">=6"
             }
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
             "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
             "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
-            "dev": true
-        },
-        "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==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=0.8.0"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/escodegen": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
-            "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
+        "node_modules/escape-string-regexp": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+            "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "esprima": "^4.0.1",
-                "estraverse": "^5.2.0",
-                "esutils": "^2.0.2"
-            },
-            "bin": {
-                "escodegen": "bin/escodegen.js",
-                "esgenerate": "bin/esgenerate.js"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=6.0"
+                "node": ">=10"
             },
             },
-            "optionalDependencies": {
-                "source-map": "~0.6.1"
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
         "node_modules/eslint": {
             }
         },
         "node_modules/eslint": {
-            "version": "8.48.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz",
-            "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==",
+            "version": "9.29.0",
+            "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.29.0.tgz",
+            "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@eslint-community/eslint-utils": "^4.2.0",
             "dependencies": {
                 "@eslint-community/eslint-utils": "^4.2.0",
-                "@eslint-community/regexpp": "^4.6.1",
-                "@eslint/eslintrc": "^2.1.2",
-                "@eslint/js": "8.48.0",
-                "@humanwhocodes/config-array": "^0.11.10",
+                "@eslint-community/regexpp": "^4.12.1",
+                "@eslint/config-array": "^0.20.1",
+                "@eslint/config-helpers": "^0.2.1",
+                "@eslint/core": "^0.14.0",
+                "@eslint/eslintrc": "^3.3.1",
+                "@eslint/js": "9.29.0",
+                "@eslint/plugin-kit": "^0.3.1",
+                "@humanfs/node": "^0.16.6",
                 "@humanwhocodes/module-importer": "^1.0.1",
                 "@humanwhocodes/module-importer": "^1.0.1",
-                "@nodelib/fs.walk": "^1.2.8",
+                "@humanwhocodes/retry": "^0.4.2",
+                "@types/estree": "^1.0.6",
+                "@types/json-schema": "^7.0.15",
                 "ajv": "^6.12.4",
                 "chalk": "^4.0.0",
                 "ajv": "^6.12.4",
                 "chalk": "^4.0.0",
-                "cross-spawn": "^7.0.2",
+                "cross-spawn": "^7.0.6",
                 "debug": "^4.3.2",
                 "debug": "^4.3.2",
-                "doctrine": "^3.0.0",
                 "escape-string-regexp": "^4.0.0",
                 "escape-string-regexp": "^4.0.0",
-                "eslint-scope": "^7.2.2",
-                "eslint-visitor-keys": "^3.4.3",
-                "espree": "^9.6.1",
-                "esquery": "^1.4.2",
+                "eslint-scope": "^8.4.0",
+                "eslint-visitor-keys": "^4.2.1",
+                "espree": "^10.4.0",
+                "esquery": "^1.5.0",
                 "esutils": "^2.0.2",
                 "fast-deep-equal": "^3.1.3",
                 "esutils": "^2.0.2",
                 "fast-deep-equal": "^3.1.3",
-                "file-entry-cache": "^6.0.1",
+                "file-entry-cache": "^8.0.0",
                 "find-up": "^5.0.0",
                 "glob-parent": "^6.0.2",
                 "find-up": "^5.0.0",
                 "glob-parent": "^6.0.2",
-                "globals": "^13.19.0",
-                "graphemer": "^1.4.0",
                 "ignore": "^5.2.0",
                 "imurmurhash": "^0.1.4",
                 "is-glob": "^4.0.0",
                 "ignore": "^5.2.0",
                 "imurmurhash": "^0.1.4",
                 "is-glob": "^4.0.0",
-                "is-path-inside": "^3.0.3",
-                "js-yaml": "^4.1.0",
                 "json-stable-stringify-without-jsonify": "^1.0.1",
                 "json-stable-stringify-without-jsonify": "^1.0.1",
-                "levn": "^0.4.1",
                 "lodash.merge": "^4.6.2",
                 "minimatch": "^3.1.2",
                 "natural-compare": "^1.4.0",
                 "lodash.merge": "^4.6.2",
                 "minimatch": "^3.1.2",
                 "natural-compare": "^1.4.0",
-                "optionator": "^0.9.3",
-                "strip-ansi": "^6.0.1",
-                "text-table": "^0.2.0"
+                "optionator": "^0.9.3"
             },
             "bin": {
                 "eslint": "bin/eslint.js"
             },
             "engines": {
             },
             "bin": {
                 "eslint": "bin/eslint.js"
             },
             "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://opencollective.com/eslint"
+                "url": "https://eslint.org/donate"
+            },
+            "peerDependencies": {
+                "jiti": "*"
+            },
+            "peerDependenciesMeta": {
+                "jiti": {
+                    "optional": true
+                }
             }
         },
         "node_modules/eslint-import-resolver-node": {
             }
         },
         "node_modules/eslint-import-resolver-node": {
             "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
             "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
             "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "debug": "^3.2.7",
                 "is-core-module": "^2.13.0",
             "dependencies": {
                 "debug": "^3.2.7",
                 "is-core-module": "^2.13.0",
             "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
             "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
             "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ms": "^2.1.1"
             }
         },
         "node_modules/eslint-module-utils": {
             "dependencies": {
                 "ms": "^2.1.1"
             }
         },
         "node_modules/eslint-module-utils": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz",
-            "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==",
+            "version": "2.12.1",
+            "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
+            "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "debug": "^3.2.7"
             },
             "dependencies": {
                 "debug": "^3.2.7"
             },
             "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
             "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
             "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ms": "^2.1.1"
             }
         },
         "node_modules/eslint-plugin-import": {
             "dependencies": {
                 "ms": "^2.1.1"
             }
         },
         "node_modules/eslint-plugin-import": {
-            "version": "2.28.1",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz",
-            "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==",
+            "version": "2.32.0",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
+            "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "array-includes": "^3.1.6",
-                "array.prototype.findlastindex": "^1.2.2",
-                "array.prototype.flat": "^1.3.1",
-                "array.prototype.flatmap": "^1.3.1",
+                "@rtsao/scc": "^1.1.0",
+                "array-includes": "^3.1.9",
+                "array.prototype.findlastindex": "^1.2.6",
+                "array.prototype.flat": "^1.3.3",
+                "array.prototype.flatmap": "^1.3.3",
                 "debug": "^3.2.7",
                 "doctrine": "^2.1.0",
                 "debug": "^3.2.7",
                 "doctrine": "^2.1.0",
-                "eslint-import-resolver-node": "^0.3.7",
-                "eslint-module-utils": "^2.8.0",
-                "has": "^1.0.3",
-                "is-core-module": "^2.13.0",
+                "eslint-import-resolver-node": "^0.3.9",
+                "eslint-module-utils": "^2.12.1",
+                "hasown": "^2.0.2",
+                "is-core-module": "^2.16.1",
                 "is-glob": "^4.0.3",
                 "minimatch": "^3.1.2",
                 "is-glob": "^4.0.3",
                 "minimatch": "^3.1.2",
-                "object.fromentries": "^2.0.6",
-                "object.groupby": "^1.0.0",
-                "object.values": "^1.1.6",
+                "object.fromentries": "^2.0.8",
+                "object.groupby": "^1.0.3",
+                "object.values": "^1.2.1",
                 "semver": "^6.3.1",
                 "semver": "^6.3.1",
-                "tsconfig-paths": "^3.14.2"
+                "string.prototype.trimend": "^1.0.9",
+                "tsconfig-paths": "^3.15.0"
             },
             "engines": {
                 "node": ">=4"
             },
             "peerDependencies": {
             },
             "engines": {
                 "node": ">=4"
             },
             "peerDependencies": {
-                "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+                "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
             }
         },
         "node_modules/eslint-plugin-import/node_modules/debug": {
             }
         },
         "node_modules/eslint-plugin-import/node_modules/debug": {
             "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
             "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
             "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ms": "^2.1.1"
             }
             "dependencies": {
                 "ms": "^2.1.1"
             }
             "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
             "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
             "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
                 "esutils": "^2.0.2"
             },
             "dependencies": {
                 "esutils": "^2.0.2"
             },
             }
         },
         "node_modules/eslint-plugin-react": {
             }
         },
         "node_modules/eslint-plugin-react": {
-            "version": "7.33.2",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz",
-            "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==",
+            "version": "7.37.5",
+            "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
+            "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "array-includes": "^3.1.6",
-                "array.prototype.flatmap": "^1.3.1",
-                "array.prototype.tosorted": "^1.1.1",
+                "array-includes": "^3.1.8",
+                "array.prototype.findlast": "^1.2.5",
+                "array.prototype.flatmap": "^1.3.3",
+                "array.prototype.tosorted": "^1.1.4",
                 "doctrine": "^2.1.0",
                 "doctrine": "^2.1.0",
-                "es-iterator-helpers": "^1.0.12",
+                "es-iterator-helpers": "^1.2.1",
                 "estraverse": "^5.3.0",
                 "estraverse": "^5.3.0",
+                "hasown": "^2.0.2",
                 "jsx-ast-utils": "^2.4.1 || ^3.0.0",
                 "minimatch": "^3.1.2",
                 "jsx-ast-utils": "^2.4.1 || ^3.0.0",
                 "minimatch": "^3.1.2",
-                "object.entries": "^1.1.6",
-                "object.fromentries": "^2.0.6",
-                "object.hasown": "^1.1.2",
-                "object.values": "^1.1.6",
+                "object.entries": "^1.1.9",
+                "object.fromentries": "^2.0.8",
+                "object.values": "^1.2.1",
                 "prop-types": "^15.8.1",
                 "prop-types": "^15.8.1",
-                "resolve": "^2.0.0-next.4",
+                "resolve": "^2.0.0-next.5",
                 "semver": "^6.3.1",
                 "semver": "^6.3.1",
-                "string.prototype.matchall": "^4.0.8"
+                "string.prototype.matchall": "^4.0.12",
+                "string.prototype.repeat": "^1.0.0"
             },
             "engines": {
                 "node": ">=4"
             },
             "peerDependencies": {
             },
             "engines": {
                 "node": ">=4"
             },
             "peerDependencies": {
-                "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
+                "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
             }
         },
         "node_modules/eslint-plugin-react/node_modules/doctrine": {
             }
         },
         "node_modules/eslint-plugin-react/node_modules/doctrine": {
             "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
             "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
             "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
                 "esutils": "^2.0.2"
             },
             "dependencies": {
                 "esutils": "^2.0.2"
             },
             }
         },
         "node_modules/eslint-plugin-react/node_modules/resolve": {
             }
         },
         "node_modules/eslint-plugin-react/node_modules/resolve": {
-            "version": "2.0.0-next.4",
-            "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
-            "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
+            "version": "2.0.0-next.5",
+            "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
+            "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "is-core-module": "^2.9.0",
+                "is-core-module": "^2.13.0",
                 "path-parse": "^1.0.7",
                 "supports-preserve-symlinks-flag": "^1.0.0"
             },
                 "path-parse": "^1.0.7",
                 "supports-preserve-symlinks-flag": "^1.0.0"
             },
             "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
             "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
             "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "esrecurse": "^4.3.0",
                 "estraverse": "^4.1.1"
             "dependencies": {
                 "esrecurse": "^4.3.0",
                 "estraverse": "^4.1.1"
             "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
             "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
             "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "engines": {
                 "node": ">=4.0"
             }
             "engines": {
                 "node": ">=4.0"
             }
             "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
             "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
             "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
             "dev": true,
+            "license": "Apache-2.0",
             "engines": {
                 "node": ">=10"
             }
         },
             "engines": {
                 "node": ">=10"
             }
         },
-        "node_modules/eslint/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-            }
-        },
         "node_modules/eslint/node_modules/chalk": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
             "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
             "dev": true,
         "node_modules/eslint/node_modules/chalk": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
             "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ansi-styles": "^4.1.0",
                 "supports-color": "^7.1.0"
             "dependencies": {
                 "ansi-styles": "^4.1.0",
                 "supports-color": "^7.1.0"
                 "url": "https://github.com/chalk/chalk?sponsor=1"
             }
         },
                 "url": "https://github.com/chalk/chalk?sponsor=1"
             }
         },
-        "node_modules/eslint/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/eslint/node_modules/eslint-scope": {
+            "version": "8.4.0",
+            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz",
+            "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==",
             "dev": true,
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "esrecurse": "^4.3.0",
+                "estraverse": "^5.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/eslint/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/eslint/node_modules/escape-string-regexp": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-            "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-            "dev": true,
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
-        "node_modules/eslint/node_modules/eslint-scope": {
-            "version": "7.2.2",
-            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
-            "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
-            "dev": true,
-            "dependencies": {
-                "esrecurse": "^4.3.0",
-                "estraverse": "^5.2.0"
-            },
-            "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-            },
-            "funding": {
-                "url": "https://opencollective.com/eslint"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/eslint"
             }
         },
         "node_modules/eslint/node_modules/eslint-visitor-keys": {
             }
         },
         "node_modules/eslint/node_modules/eslint-visitor-keys": {
-            "version": "3.4.3",
-            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-            "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+            "version": "4.2.1",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+            "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
             "funding": {
                 "url": "https://opencollective.com/eslint"
             }
         },
             },
             "funding": {
                 "url": "https://opencollective.com/eslint"
             }
         },
-        "node_modules/eslint/node_modules/globals": {
-            "version": "13.21.0",
-            "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
-            "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
-            "dev": true,
-            "dependencies": {
-                "type-fest": "^0.20.2"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
-        "node_modules/eslint/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/eslint/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-            "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/espree": {
         "node_modules/espree": {
-            "version": "9.6.1",
-            "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
-            "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+            "version": "10.4.0",
+            "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz",
+            "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==",
             "dev": true,
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
             "dependencies": {
-                "acorn": "^8.9.0",
+                "acorn": "^8.15.0",
                 "acorn-jsx": "^5.3.2",
                 "acorn-jsx": "^5.3.2",
-                "eslint-visitor-keys": "^3.4.1"
+                "eslint-visitor-keys": "^4.2.1"
             },
             "engines": {
             },
             "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
             "funding": {
                 "url": "https://opencollective.com/eslint"
             }
         },
         "node_modules/espree/node_modules/eslint-visitor-keys": {
             },
             "funding": {
                 "url": "https://opencollective.com/eslint"
             }
         },
         "node_modules/espree/node_modules/eslint-visitor-keys": {
-            "version": "3.4.3",
-            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-            "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+            "version": "4.2.1",
+            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz",
+            "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==",
             "dev": true,
             "dev": true,
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+                "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
             },
             "funding": {
                 "url": "https://opencollective.com/eslint"
             }
         },
             },
             "funding": {
                 "url": "https://opencollective.com/eslint"
             }
         },
-        "node_modules/esprima": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-            "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-            "dev": true,
-            "bin": {
-                "esparse": "bin/esparse.js",
-                "esvalidate": "bin/esvalidate.js"
-            },
-            "engines": {
-                "node": ">=4"
-            }
-        },
         "node_modules/esquery": {
         "node_modules/esquery": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
-            "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+            "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
             "dev": true,
             "dev": true,
+            "license": "BSD-3-Clause",
             "dependencies": {
                 "estraverse": "^5.1.0"
             },
             "dependencies": {
                 "estraverse": "^5.1.0"
             },
             "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
             "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
             "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "estraverse": "^5.2.0"
             },
             "dependencies": {
                 "estraverse": "^5.2.0"
             },
             "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
             "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
             "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "engines": {
                 "node": ">=4.0"
             }
         },
             "engines": {
                 "node": ">=4.0"
             }
         },
+        "node_modules/estree-walker": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+            "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+            "dev": true,
+            "license": "MIT"
+        },
         "node_modules/esutils": {
             "version": "2.0.3",
             "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
             "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
             "dev": true,
         "node_modules/esutils": {
             "version": "2.0.3",
             "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
             "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "engines": {
                 "node": ">=0.10.0"
             }
             "engines": {
                 "node": ">=0.10.0"
             }
             "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
             "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
             "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.6"
             }
             "engines": {
                 "node": ">= 0.6"
             }
         "node_modules/eventemitter3": {
             "version": "4.0.7",
             "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
         "node_modules/eventemitter3": {
             "version": "4.0.7",
             "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
-            "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+            "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+            "license": "MIT"
         },
         "node_modules/events": {
             "version": "3.3.0",
             "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
             "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
             "dev": true,
         },
         "node_modules/events": {
             "version": "3.3.0",
             "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
             "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.8.x"
             }
             "engines": {
                 "node": ">=0.8.x"
             }
             "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
             "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
             "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "md5.js": "^1.3.4",
                 "safe-buffer": "^5.1.1"
             "dependencies": {
                 "md5.js": "^1.3.4",
                 "safe-buffer": "^5.1.1"
             "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
             "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
             "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "cross-spawn": "^7.0.3",
                 "get-stream": "^6.0.0",
             "dependencies": {
                 "cross-spawn": "^7.0.3",
                 "get-stream": "^6.0.0",
                 "url": "https://github.com/sindresorhus/execa?sponsor=1"
             }
         },
                 "url": "https://github.com/sindresorhus/execa?sponsor=1"
             }
         },
-        "node_modules/exit": {
-            "version": "0.1.2",
-            "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
-            "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.8.0"
-            }
-        },
-        "node_modules/expect": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
-            "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
+        "node_modules/expect-type": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz",
+            "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@jest/expect-utils": "^29.7.0",
-                "jest-get-type": "^29.6.3",
-                "jest-matcher-utils": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-util": "^29.7.0"
-            },
+            "license": "Apache-2.0",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=12.0.0"
             }
         },
         "node_modules/express": {
             }
         },
         "node_modules/express": {
-            "version": "4.18.2",
-            "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
-            "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+            "version": "4.21.2",
+            "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
+            "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "accepts": "~1.3.8",
                 "array-flatten": "1.1.1",
             "dependencies": {
                 "accepts": "~1.3.8",
                 "array-flatten": "1.1.1",
-                "body-parser": "1.20.1",
+                "body-parser": "1.20.3",
                 "content-disposition": "0.5.4",
                 "content-type": "~1.0.4",
                 "content-disposition": "0.5.4",
                 "content-type": "~1.0.4",
-                "cookie": "0.5.0",
+                "cookie": "0.7.1",
                 "cookie-signature": "1.0.6",
                 "debug": "2.6.9",
                 "depd": "2.0.0",
                 "cookie-signature": "1.0.6",
                 "debug": "2.6.9",
                 "depd": "2.0.0",
-                "encodeurl": "~1.0.2",
+                "encodeurl": "~2.0.0",
                 "escape-html": "~1.0.3",
                 "etag": "~1.8.1",
                 "escape-html": "~1.0.3",
                 "etag": "~1.8.1",
-                "finalhandler": "1.2.0",
+                "finalhandler": "1.3.1",
                 "fresh": "0.5.2",
                 "http-errors": "2.0.0",
                 "fresh": "0.5.2",
                 "http-errors": "2.0.0",
-                "merge-descriptors": "1.0.1",
+                "merge-descriptors": "1.0.3",
                 "methods": "~1.1.2",
                 "on-finished": "2.4.1",
                 "parseurl": "~1.3.3",
                 "methods": "~1.1.2",
                 "on-finished": "2.4.1",
                 "parseurl": "~1.3.3",
-                "path-to-regexp": "0.1.7",
+                "path-to-regexp": "0.1.12",
                 "proxy-addr": "~2.0.7",
                 "proxy-addr": "~2.0.7",
-                "qs": "6.11.0",
+                "qs": "6.13.0",
                 "range-parser": "~1.2.1",
                 "safe-buffer": "5.2.1",
                 "range-parser": "~1.2.1",
                 "safe-buffer": "5.2.1",
-                "send": "0.18.0",
-                "serve-static": "1.15.0",
+                "send": "0.19.0",
+                "serve-static": "1.16.2",
                 "setprototypeof": "1.2.0",
                 "statuses": "2.0.1",
                 "type-is": "~1.6.18",
                 "setprototypeof": "1.2.0",
                 "statuses": "2.0.1",
                 "type-is": "~1.6.18",
             },
             "engines": {
                 "node": ">= 0.10.0"
             },
             "engines": {
                 "node": ">= 0.10.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/express"
             }
         },
             }
         },
-        "node_modules/express/node_modules/array-flatten": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
-            "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
-            "dev": true
-        },
         "node_modules/express/node_modules/debug": {
             "version": "2.6.9",
             "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
             "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
         "node_modules/express/node_modules/debug": {
             "version": "2.6.9",
             "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
             "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ms": "2.0.0"
             }
             "dependencies": {
                 "ms": "2.0.0"
             }
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
             "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
             "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/express/node_modules/qs": {
         },
         "node_modules/express/node_modules/qs": {
-            "version": "6.11.0",
-            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
-            "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+            "version": "6.13.0",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
+            "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
             "dev": true,
             "dev": true,
+            "license": "BSD-3-Clause",
             "dependencies": {
             "dependencies": {
-                "side-channel": "^1.0.4"
+                "side-channel": "^1.0.6"
             },
             "engines": {
                 "node": ">=0.6"
             },
             "engines": {
                 "node": ">=0.6"
             "version": "3.1.3",
             "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
             "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
             "version": "3.1.3",
             "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
             "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/fast-equals": {
         },
         "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==",
+            "version": "5.2.2",
+            "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz",
+            "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==",
+            "license": "MIT",
             "engines": {
                 "node": ">=6.0.0"
             }
         },
         "node_modules/fast-glob": {
             "engines": {
                 "node": ">=6.0.0"
             }
         },
         "node_modules/fast-glob": {
-            "version": "3.3.1",
-            "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
-            "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
+            "version": "3.3.3",
+            "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+            "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@nodelib/fs.stat": "^2.0.2",
                 "@nodelib/fs.walk": "^1.2.3",
                 "glob-parent": "^5.1.2",
                 "merge2": "^1.3.0",
             "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"
+                "micromatch": "^4.0.8"
             },
             "engines": {
                 "node": ">=8.6.0"
             },
             "engines": {
                 "node": ">=8.6.0"
             "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
             "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
             "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
             "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "is-glob": "^4.0.1"
             },
             "dependencies": {
                 "is-glob": "^4.0.1"
             },
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
             "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
             "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/fast-levenshtein": {
             "version": "2.0.6",
             "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
             "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
         },
         "node_modules/fast-levenshtein": {
             "version": "2.0.6",
             "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
             "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/fast-uri": {
+            "version": "3.0.6",
+            "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
+            "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
+            "dev": true,
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/fastify"
+                },
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/fastify"
+                }
+            ],
+            "license": "BSD-3-Clause"
         },
         "node_modules/fastest-levenshtein": {
             "version": "1.0.16",
             "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
             "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
             "dev": true,
         },
         "node_modules/fastest-levenshtein": {
             "version": "1.0.16",
             "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
             "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 4.9.1"
             }
         },
         "node_modules/fastq": {
             "engines": {
                 "node": ">= 4.9.1"
             }
         },
         "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==",
+            "version": "1.19.1",
+            "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+            "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "reusify": "^1.0.4"
             }
             "dependencies": {
                 "reusify": "^1.0.4"
             }
             "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
             "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
             "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
             "dev": true,
+            "license": "Apache-2.0",
             "dependencies": {
                 "websocket-driver": ">=0.5.1"
             },
             "dependencies": {
                 "websocket-driver": ">=0.5.1"
             },
                 "node": ">=0.8.0"
             }
         },
                 "node": ">=0.8.0"
             }
         },
-        "node_modules/fb-watchman": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
-            "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
-            "dev": true,
-            "dependencies": {
-                "bser": "2.1.1"
-            }
-        },
         "node_modules/file-entry-cache": {
         "node_modules/file-entry-cache": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
-            "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+            "version": "8.0.0",
+            "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+            "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "flat-cache": "^3.0.4"
+                "flat-cache": "^4.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10.12.0 || >=12.0.0"
+                "node": ">=16.0.0"
             }
         },
         "node_modules/file-loader": {
             }
         },
         "node_modules/file-loader": {
             "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
             "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
             "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "loader-utils": "^2.0.0",
                 "schema-utils": "^3.0.0"
             "dependencies": {
                 "loader-utils": "^2.0.0",
                 "schema-utils": "^3.0.0"
             "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
             "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
             "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/json-schema": "^7.0.8",
                 "ajv": "^6.12.5",
             "dependencies": {
                 "@types/json-schema": "^7.0.8",
                 "ajv": "^6.12.5",
         "node_modules/file-saver": {
             "version": "2.0.5",
             "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
         "node_modules/file-saver": {
             "version": "2.0.5",
             "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
-            "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
+            "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==",
+            "license": "MIT"
         },
         "node_modules/file-type": {
             "version": "12.4.2",
             "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz",
             "integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==",
             "dev": true,
         },
         "node_modules/file-type": {
             "version": "12.4.2",
             "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz",
             "integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             }
         },
         "node_modules/fill-range": {
             "engines": {
                 "node": ">=8"
             }
         },
         "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==",
+            "version": "7.1.1",
+            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+            "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "to-regex-range": "^5.0.1"
             },
             "dependencies": {
                 "to-regex-range": "^5.0.1"
             },
             }
         },
         "node_modules/finalhandler": {
             }
         },
         "node_modules/finalhandler": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
-            "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
+            "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "debug": "2.6.9",
             "dependencies": {
                 "debug": "2.6.9",
-                "encodeurl": "~1.0.2",
+                "encodeurl": "~2.0.0",
                 "escape-html": "~1.0.3",
                 "on-finished": "2.4.1",
                 "parseurl": "~1.3.3",
                 "escape-html": "~1.0.3",
                 "on-finished": "2.4.1",
                 "parseurl": "~1.3.3",
             "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
             "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
             "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ms": "2.0.0"
             }
             "dependencies": {
                 "ms": "2.0.0"
             }
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
             "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
             "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/find-cache-dir": {
             "version": "3.3.2",
             "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
             "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
             "dev": true,
         },
         "node_modules/find-cache-dir": {
             "version": "3.3.2",
             "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
             "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "commondir": "^1.0.1",
                 "make-dir": "^3.0.2",
             "dependencies": {
                 "commondir": "^1.0.1",
                 "make-dir": "^3.0.2",
             "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
             "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
             "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "locate-path": "^6.0.0",
                 "path-exists": "^4.0.0"
             "dependencies": {
                 "locate-path": "^6.0.0",
                 "path-exists": "^4.0.0"
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
                 "url": "https://github.com/sponsors/sindresorhus"
             }
         },
+        "node_modules/flat": {
+            "version": "5.0.2",
+            "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+            "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+            "dev": true,
+            "license": "BSD-3-Clause",
+            "bin": {
+                "flat": "cli.js"
+            }
+        },
         "node_modules/flat-cache": {
         "node_modules/flat-cache": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz",
-            "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==",
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+            "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "flatted": "^3.2.7",
-                "keyv": "^4.5.3",
-                "rimraf": "^3.0.2"
+                "flatted": "^3.2.9",
+                "keyv": "^4.5.4"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=12.0.0"
+                "node": ">=16"
             }
         },
         "node_modules/flatted": {
             }
         },
         "node_modules/flatted": {
-            "version": "3.2.7",
-            "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
-            "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
-            "dev": true
+            "version": "3.3.3",
+            "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+            "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+            "dev": true,
+            "license": "ISC"
         },
         "node_modules/follow-redirects": {
         },
         "node_modules/follow-redirects": {
-            "version": "1.15.2",
-            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
-            "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+            "version": "1.15.9",
+            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+            "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
             "dev": true,
             "funding": [
                 {
             "dev": true,
             "funding": [
                 {
                     "url": "https://github.com/sponsors/RubenVerborgh"
                 }
             ],
                     "url": "https://github.com/sponsors/RubenVerborgh"
                 }
             ],
+            "license": "MIT",
             "engines": {
                 "node": ">=4.0"
             },
             "engines": {
                 "node": ">=4.0"
             },
             }
         },
         "node_modules/for-each": {
             }
         },
         "node_modules/for-each": {
-            "version": "0.3.3",
-            "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
-            "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+            "version": "0.3.5",
+            "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+            "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "is-callable": "^1.2.7"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/foreground-child": {
+            "version": "3.3.1",
+            "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+            "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "is-callable": "^1.1.3"
+                "cross-spawn": "^7.0.6",
+                "signal-exit": "^4.0.1"
+            },
+            "engines": {
+                "node": ">=14"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
+            }
+        },
+        "node_modules/foreground-child/node_modules/signal-exit": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+            "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+            "dev": true,
+            "license": "ISC",
+            "engines": {
+                "node": ">=14"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
             }
         },
         "node_modules/form-data": {
             }
         },
         "node_modules/form-data": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
-            "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+            "version": "4.0.3",
+            "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz",
+            "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "asynckit": "^0.4.0",
                 "combined-stream": "^1.0.8",
             "dependencies": {
                 "asynckit": "^0.4.0",
                 "combined-stream": "^1.0.8",
+                "es-set-tostringtag": "^2.1.0",
+                "hasown": "^2.0.2",
                 "mime-types": "^2.1.12"
             },
             "engines": {
                 "mime-types": "^2.1.12"
             },
             "engines": {
             }
         },
         "node_modules/formik": {
             }
         },
         "node_modules/formik": {
-            "version": "2.4.3",
-            "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.3.tgz",
-            "integrity": "sha512-2Dy79Szw3zlXmZiokUdKsn+n1ow4G8hRrC/n92cOWHNTWXCRpQXlyvz6HcjW7aSQZrldytvDOavYjhfmDnUq8Q==",
+            "version": "2.4.6",
+            "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz",
+            "integrity": "sha512-A+2EI7U7aG296q2TLGvNapDNTZp1khVt5Vk0Q/fyfSROss0V/V6+txt2aJnwEos44IxTCW/LYAi/zgWzlevj+g==",
             "funding": [
                 {
                     "type": "individual",
                     "url": "https://opencollective.com/formik"
                 }
             ],
             "funding": [
                 {
                     "type": "individual",
                     "url": "https://opencollective.com/formik"
                 }
             ],
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
+                "@types/hoist-non-react-statics": "^3.3.1",
                 "deepmerge": "^2.1.1",
                 "hoist-non-react-statics": "^3.3.0",
                 "lodash": "^4.17.21",
                 "deepmerge": "^2.1.1",
                 "hoist-non-react-statics": "^3.3.0",
                 "lodash": "^4.17.21",
             "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
             "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
             "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.6"
             }
         },
         "node_modules/fraction.js": {
             "engines": {
                 "node": ">= 0.6"
             }
         },
         "node_modules/fraction.js": {
-            "version": "4.3.6",
-            "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz",
-            "integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==",
+            "version": "4.3.7",
+            "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+            "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": "*"
             },
             "engines": {
                 "node": "*"
             },
             "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
             "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
             "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.6"
             }
             "engines": {
                 "node": ">= 0.6"
             }
             "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
             "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
             "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "graceful-fs": "^4.2.0",
                 "jsonfile": "^6.0.1",
             "dependencies": {
                 "graceful-fs": "^4.2.0",
                 "jsonfile": "^6.0.1",
             }
         },
         "node_modules/fs-monkey": {
             }
         },
         "node_modules/fs-monkey": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz",
-            "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==",
-            "dev": true
+            "version": "1.0.6",
+            "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz",
+            "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==",
+            "dev": true,
+            "license": "Unlicense"
         },
         "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/fs.realpath": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
             "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-            "dev": true
+            "dev": true,
+            "license": "ISC"
         },
         "node_modules/fsevents": {
             "version": "2.3.3",
         },
         "node_modules/fsevents": {
             "version": "2.3.3",
             "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
             "dev": true,
             "hasInstallScript": true,
             "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
             "dev": true,
             "hasInstallScript": true,
+            "license": "MIT",
             "optional": true,
             "os": [
                 "darwin"
             "optional": true,
             "os": [
                 "darwin"
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
             "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
             "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+            "license": "MIT",
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/function.prototype.name": {
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/function.prototype.name": {
-            "version": "1.1.6",
-            "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
-            "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
+            "version": "1.1.8",
+            "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz",
+            "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "functions-have-names": "^1.2.3"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.3",
+                "define-properties": "^1.2.1",
+                "functions-have-names": "^1.2.3",
+                "hasown": "^2.0.2",
+                "is-callable": "^1.2.7"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
             "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
             "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
             "dev": true,
+            "license": "MIT",
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
+        "node_modules/fuzzy-search": {
+            "version": "3.2.1",
+            "resolved": "https://registry.npmjs.org/fuzzy-search/-/fuzzy-search-3.2.1.tgz",
+            "integrity": "sha512-vAcPiyomt1ioKAsAL2uxSABHJ4Ju/e4UeDM+g1OlR0vV4YhLGMNsdLNvZTpEDY4JCSt0E4hASCNM5t2ETtsbyg==",
+            "license": "ISC"
+        },
         "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==",
             "dev": true,
         "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==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=6.9.0"
             }
             "engines": {
                 "node": ">=6.9.0"
             }
             "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
             "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
             "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
             "dev": true,
+            "license": "ISC",
             "engines": {
                 "node": "6.* || 8.* || >= 10.*"
             }
         },
         "node_modules/get-intrinsic": {
             "engines": {
                 "node": "6.* || 8.* || >= 10.*"
             }
         },
         "node_modules/get-intrinsic": {
-            "version": "1.2.4",
-            "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
-            "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+            "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
+                "call-bind-apply-helpers": "^1.0.2",
+                "es-define-property": "^1.0.1",
                 "es-errors": "^1.3.0",
                 "es-errors": "^1.3.0",
+                "es-object-atoms": "^1.1.1",
                 "function-bind": "^1.1.2",
                 "function-bind": "^1.1.2",
-                "has-proto": "^1.0.1",
-                "has-symbols": "^1.0.3",
-                "hasown": "^2.0.0"
+                "get-proto": "^1.0.1",
+                "gopd": "^1.2.0",
+                "has-symbols": "^1.1.0",
+                "hasown": "^2.0.2",
+                "math-intrinsics": "^1.1.0"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/get-package-type": {
-            "version": "0.1.0",
-            "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
-            "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
-            "dev": true,
+        "node_modules/get-proto": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+            "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+            "license": "MIT",
+            "dependencies": {
+                "dunder-proto": "^1.0.1",
+                "es-object-atoms": "^1.0.0"
+            },
             "engines": {
             "engines": {
-                "node": ">=8.0.0"
+                "node": ">= 0.4"
             }
         },
         "node_modules/get-stream": {
             }
         },
         "node_modules/get-stream": {
             "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
             "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
             "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=10"
             },
             "engines": {
                 "node": ">=10"
             },
             }
         },
         "node_modules/get-symbol-description": {
             }
         },
         "node_modules/get-symbol-description": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
-            "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz",
+            "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.1.1"
+                "call-bound": "^1.0.3",
+                "es-errors": "^1.3.0",
+                "get-intrinsic": "^1.2.6"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "version": "7.2.3",
             "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
             "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
             "version": "7.2.3",
             "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
             "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+            "deprecated": "Glob versions prior to v9 are no longer supported",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "fs.realpath": "^1.0.0",
                 "inflight": "^1.0.4",
             "dependencies": {
                 "fs.realpath": "^1.0.0",
                 "inflight": "^1.0.4",
             "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
             "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
             "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
             "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "is-glob": "^4.0.3"
             },
             "dependencies": {
                 "is-glob": "^4.0.3"
             },
             "version": "0.4.1",
             "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
             "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
             "version": "0.4.1",
             "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
             "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
-            "dev": true
+            "dev": true,
+            "license": "BSD-2-Clause"
         },
         "node_modules/globals": {
         },
         "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==",
+            "version": "16.2.0",
+            "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
+            "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=4"
+                "node": ">=18"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
         "node_modules/globalthis": {
             }
         },
         "node_modules/globalthis": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
-            "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+            "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "define-properties": "^1.1.3"
+                "define-properties": "^1.2.1",
+                "gopd": "^1.0.1"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz",
             "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz",
             "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/glob": "^7.1.1",
                 "array-union": "^2.1.0",
             "dependencies": {
                 "@types/glob": "^7.1.1",
                 "array-union": "^2.1.0",
             }
         },
         "node_modules/gopd": {
             }
         },
         "node_modules/gopd": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
-            "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
-            "dependencies": {
-                "get-intrinsic": "^1.1.3"
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+            "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             "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==",
             "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==",
-            "dev": true
-        },
-        "node_modules/graphemer": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
-            "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
-            "dev": true
+            "dev": true,
+            "license": "ISC"
         },
         "node_modules/growly": {
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
             "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==",
         },
         "node_modules/growly": {
             "version": "1.3.0",
             "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
             "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/handle-thing": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
             "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
         },
         "node_modules/handle-thing": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
             "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
-            "dev": true
-        },
-        "node_modules/has": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-            "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "function-bind": "^1.1.1"
-            },
-            "engines": {
-                "node": ">= 0.4.0"
-            }
+            "license": "MIT"
         },
         "node_modules/has-bigints": {
         },
         "node_modules/has-bigints": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
-            "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
+            "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4"
+            },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/has-flag": {
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "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==",
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=4"
+                "node": ">=8"
             }
         },
         "node_modules/has-property-descriptors": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
             "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
             }
         },
         "node_modules/has-property-descriptors": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
             "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "es-define-property": "^1.0.0"
             },
             "dependencies": {
                 "es-define-property": "^1.0.0"
             },
             }
         },
         "node_modules/has-proto": {
             }
         },
         "node_modules/has-proto": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
-            "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz",
+            "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "dunder-proto": "^1.0.0"
+            },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             }
         },
         "node_modules/has-symbols": {
             }
         },
         "node_modules/has-symbols": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
-            "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+            "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
             "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
             "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "has-symbols": "^1.0.3"
             },
             "dependencies": {
                 "has-symbols": "^1.0.3"
             },
             }
         },
         "node_modules/hash-base": {
             }
         },
         "node_modules/hash-base": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
-            "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+            "version": "3.0.5",
+            "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz",
+            "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "inherits": "^2.0.4",
             "dependencies": {
                 "inherits": "^2.0.4",
-                "readable-stream": "^3.6.0",
-                "safe-buffer": "^5.2.0"
+                "safe-buffer": "^5.2.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/hash-base/node_modules/readable-stream": {
-            "version": "3.6.2",
-            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-            "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
-            "dev": true,
-            "dependencies": {
-                "inherits": "^2.0.3",
-                "string_decoder": "^1.1.1",
-                "util-deprecate": "^1.0.1"
-            },
-            "engines": {
-                "node": ">= 6"
+                "node": ">= 0.10"
             }
         },
         "node_modules/hash-sum": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
             "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
             }
         },
         "node_modules/hash-sum": {
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
             "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/hash.js": {
             "version": "1.1.7",
             "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
             "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
             "dev": true,
         },
         "node_modules/hash.js": {
             "version": "1.1.7",
             "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
             "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "inherits": "^2.0.3",
                 "minimalistic-assert": "^1.0.1"
             }
         },
         "node_modules/hasown": {
             "dependencies": {
                 "inherits": "^2.0.3",
                 "minimalistic-assert": "^1.0.1"
             }
         },
         "node_modules/hasown": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
-            "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+            "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+            "license": "MIT",
             "dependencies": {
                 "function-bind": "^1.1.2"
             },
             "dependencies": {
                 "function-bind": "^1.1.2"
             },
             "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
             "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
             "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
             "dev": true,
+            "license": "MIT",
             "bin": {
                 "he": "bin/he"
             }
             "bin": {
                 "he": "bin/he"
             }
             "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
             "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
             "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "hash.js": "^1.0.3",
                 "minimalistic-assert": "^1.0.0",
             "dependencies": {
                 "hash.js": "^1.0.3",
                 "minimalistic-assert": "^1.0.0",
             "version": "3.3.2",
             "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
             "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
             "version": "3.3.2",
             "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
             "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+            "license": "BSD-3-Clause",
             "dependencies": {
                 "react-is": "^16.7.0"
             }
             "dependencies": {
                 "react-is": "^16.7.0"
             }
             "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
             "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
             "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "inherits": "^2.0.1",
                 "obuf": "^1.0.0",
             "dependencies": {
                 "inherits": "^2.0.1",
                 "obuf": "^1.0.0",
             }
         },
         "node_modules/html-encoding-sniffer": {
             }
         },
         "node_modules/html-encoding-sniffer": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
-            "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+            "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "whatwg-encoding": "^2.0.0"
+                "whatwg-encoding": "^3.1.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=12"
+                "node": ">=18"
             }
         },
         "node_modules/html-entities": {
             }
         },
         "node_modules/html-entities": {
-            "version": "2.4.0",
-            "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
-            "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==",
+            "version": "2.6.0",
+            "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz",
+            "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==",
             "dev": true,
             "funding": [
                 {
             "dev": true,
             "funding": [
                 {
                     "type": "patreon",
                     "url": "https://patreon.com/mdevils"
                 }
                     "type": "patreon",
                     "url": "https://patreon.com/mdevils"
                 }
-            ]
+            ],
+            "license": "MIT"
         },
         "node_modules/html-escaper": {
             "version": "2.0.2",
             "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
             "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
         },
         "node_modules/html-escaper": {
             "version": "2.0.2",
             "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
             "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/html-loader": {
             "version": "1.3.2",
             "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-1.3.2.tgz",
             "integrity": "sha512-DEkUwSd0sijK5PF3kRWspYi56XP7bTNkyg5YWSzBdjaSDmvCufep5c4Vpb3PBf6lUL0YPtLwBfy9fL0t5hBAGA==",
             "dev": true,
         },
         "node_modules/html-loader": {
             "version": "1.3.2",
             "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-1.3.2.tgz",
             "integrity": "sha512-DEkUwSd0sijK5PF3kRWspYi56XP7bTNkyg5YWSzBdjaSDmvCufep5c4Vpb3PBf6lUL0YPtLwBfy9fL0t5hBAGA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "html-minifier-terser": "^5.1.1",
                 "htmlparser2": "^4.1.0",
             "dependencies": {
                 "html-minifier-terser": "^5.1.1",
                 "htmlparser2": "^4.1.0",
             "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
             "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
             "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/json-schema": "^7.0.8",
                 "ajv": "^6.12.5",
             "dependencies": {
                 "@types/json-schema": "^7.0.8",
                 "ajv": "^6.12.5",
             "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
             "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
             "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "camel-case": "^4.1.1",
                 "clean-css": "^4.2.3",
             "dependencies": {
                 "camel-case": "^4.1.1",
                 "clean-css": "^4.2.3",
             "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz",
             "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz",
             "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "source-map": "~0.6.0"
             },
             "dependencies": {
                 "source-map": "~0.6.0"
             },
             "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
             "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
             "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 6"
             }
             "engines": {
                 "node": ">= 6"
             }
             "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz",
             "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz",
             "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==",
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
                 "commander": "^2.20.0",
                 "source-map": "~0.6.1",
             "dependencies": {
                 "commander": "^2.20.0",
                 "source-map": "~0.6.1",
             "version": "2.20.3",
             "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
             "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
             "version": "2.20.3",
             "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
             "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/html-parse-stringify": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
             "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
         },
         "node_modules/html-parse-stringify": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
             "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
+            "license": "MIT",
             "dependencies": {
                 "void-elements": "3.1.0"
             }
             "dependencies": {
                 "void-elements": "3.1.0"
             }
             "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
             "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
             "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "domelementtype": "^2.0.1",
                 "domhandler": "^3.0.0",
             "dependencies": {
                 "domelementtype": "^2.0.1",
                 "domhandler": "^3.0.0",
             "version": "1.2.7",
             "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
             "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==",
             "version": "1.2.7",
             "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
             "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/http-errors": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
             "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
             "dev": true,
         },
         "node_modules/http-errors": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
             "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "depd": "2.0.0",
                 "inherits": "2.0.4",
             "dependencies": {
                 "depd": "2.0.0",
                 "inherits": "2.0.4",
             }
         },
         "node_modules/http-parser-js": {
             }
         },
         "node_modules/http-parser-js": {
-            "version": "0.5.8",
-            "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
-            "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
-            "dev": true
+            "version": "0.5.10",
+            "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz",
+            "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/http-proxy": {
             "version": "1.18.1",
             "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
             "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
             "dev": true,
         },
         "node_modules/http-proxy": {
             "version": "1.18.1",
             "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
             "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "eventemitter3": "^4.0.0",
                 "follow-redirects": "^1.0.0",
             "dependencies": {
                 "eventemitter3": "^4.0.0",
                 "follow-redirects": "^1.0.0",
             }
         },
         "node_modules/http-proxy-agent": {
             }
         },
         "node_modules/http-proxy-agent": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
-            "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
+            "version": "7.0.2",
+            "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+            "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@tootallnate/once": "2",
-                "agent-base": "6",
-                "debug": "4"
+                "agent-base": "^7.1.0",
+                "debug": "^4.3.4"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 6"
+                "node": ">= 14"
             }
         },
         "node_modules/http-proxy-middleware": {
             }
         },
         "node_modules/http-proxy-middleware": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz",
-            "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==",
+            "version": "2.0.9",
+            "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz",
+            "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "@types/http-proxy": "^1.17.8",
                 "http-proxy": "^1.18.1",
             "dependencies": {
                 "@types/http-proxy": "^1.17.8",
                 "http-proxy": "^1.18.1",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
             "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
             "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/https-proxy-agent": {
         },
         "node_modules/https-proxy-agent": {
-            "version": "5.0.1",
-            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
-            "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+            "version": "7.0.6",
+            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+            "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "agent-base": "6",
+                "agent-base": "^7.1.2",
                 "debug": "4"
             },
             "engines": {
                 "debug": "4"
             },
             "engines": {
-                "node": ">= 6"
+                "node": ">= 14"
             }
         },
         "node_modules/human-signals": {
             }
         },
         "node_modules/human-signals": {
             "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
             "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
             "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
             "dev": true,
+            "license": "Apache-2.0",
             "engines": {
                 "node": ">=10.17.0"
             }
         },
         "node_modules/i18next": {
             "engines": {
                 "node": ">=10.17.0"
             }
         },
         "node_modules/i18next": {
-            "version": "23.4.9",
-            "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.4.9.tgz",
-            "integrity": "sha512-F8YQ29LD6FvWS/aOYbZ4WqjDEuQZmug8akAM0QOcAtR+EuHHlBYf/JpsjeqUDdYiClmj2zE9rI9ZUWzN7W+trQ==",
+            "version": "25.2.1",
+            "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.2.1.tgz",
+            "integrity": "sha512-+UoXK5wh+VlE1Zy5p6MjcvctHXAhRwQKCxiJD8noKZzIXmnAX8gdHX5fLPA3MEVxEN4vbZkQFy8N0LyD9tUqPw==",
             "funding": [
                 {
                     "type": "individual",
             "funding": [
                 {
                     "type": "individual",
                     "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
                 }
             ],
                     "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
                 }
             ],
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/runtime": "^7.22.5"
+                "@babel/runtime": "^7.27.1"
+            },
+            "peerDependencies": {
+                "typescript": "^5"
+            },
+            "peerDependenciesMeta": {
+                "typescript": {
+                    "optional": true
+                }
             }
         },
         "node_modules/i18next-browser-languagedetector": {
             }
         },
         "node_modules/i18next-browser-languagedetector": {
-            "version": "7.1.0",
-            "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.1.0.tgz",
-            "integrity": "sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA==",
+            "version": "8.2.0",
+            "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz",
+            "integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/runtime": "^7.19.4"
+                "@babel/runtime": "^7.23.2"
             }
         },
         "node_modules/iconv-lite": {
             }
         },
         "node_modules/iconv-lite": {
             "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
             "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
             "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "safer-buffer": ">= 2.1.2 < 3"
             },
             "dependencies": {
                 "safer-buffer": ">= 2.1.2 < 3"
             },
             "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
             "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
             "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
             "dev": true,
+            "license": "ISC",
             "engines": {
                 "node": "^10 || ^12 || >= 14"
             },
             "engines": {
                 "node": "^10 || ^12 || >= 14"
             },
                     "type": "consulting",
                     "url": "https://feross.org/support"
                 }
                     "type": "consulting",
                     "url": "https://feross.org/support"
                 }
-            ]
+            ],
+            "license": "BSD-3-Clause"
         },
         "node_modules/ignore": {
         },
         "node_modules/ignore": {
-            "version": "5.2.4",
-            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
-            "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+            "version": "5.3.2",
+            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+            "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 4"
             }
             "engines": {
                 "node": ">= 4"
             }
             "resolved": "https://registry.npmjs.org/imagemin/-/imagemin-7.0.1.tgz",
             "integrity": "sha512-33AmZ+xjZhg2JMCe+vDf6a9mzWukE7l+wAtesjE7KyteqqKjzxv7aVQeWnul1Ve26mWvEQqyPwl0OctNBfSR9w==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/imagemin/-/imagemin-7.0.1.tgz",
             "integrity": "sha512-33AmZ+xjZhg2JMCe+vDf6a9mzWukE7l+wAtesjE7KyteqqKjzxv7aVQeWnul1Ve26mWvEQqyPwl0OctNBfSR9w==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "file-type": "^12.0.0",
                 "globby": "^10.0.0",
             "dependencies": {
                 "file-type": "^12.0.0",
                 "globby": "^10.0.0",
             "resolved": "https://registry.npmjs.org/img-loader/-/img-loader-4.0.0.tgz",
             "integrity": "sha512-UwRcPQdwdOyEHyCxe1V9s9YFwInwEWCpoO+kJGfIqDrBDqA8jZUsEZTxQ0JteNPGw/Gupmwesk2OhLTcnw6tnQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/img-loader/-/img-loader-4.0.0.tgz",
             "integrity": "sha512-UwRcPQdwdOyEHyCxe1V9s9YFwInwEWCpoO+kJGfIqDrBDqA8jZUsEZTxQ0JteNPGw/Gupmwesk2OhLTcnw6tnQ==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "loader-utils": "^1.1.0"
             },
             "dependencies": {
                 "loader-utils": "^1.1.0"
             },
             "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
             "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
             "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "minimist": "^1.2.0"
             },
             "dependencies": {
                 "minimist": "^1.2.0"
             },
             "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
             "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
             "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "big.js": "^5.2.2",
                 "emojis-list": "^3.0.0",
             "dependencies": {
                 "big.js": "^5.2.2",
                 "emojis-list": "^3.0.0",
         "node_modules/immediate": {
             "version": "3.0.6",
             "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
         "node_modules/immediate": {
             "version": "3.0.6",
             "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
-            "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
+            "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==",
+            "license": "MIT"
         },
         "node_modules/immutable": {
         },
         "node_modules/immutable": {
-            "version": "4.3.4",
-            "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
-            "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==",
-            "dev": true
+            "version": "5.1.3",
+            "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz",
+            "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/import-fresh": {
         },
         "node_modules/import-fresh": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
-            "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+            "version": "3.3.1",
+            "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+            "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "parent-module": "^1.0.0",
                 "resolve-from": "^4.0.0"
             "dependencies": {
                 "parent-module": "^1.0.0",
                 "resolve-from": "^4.0.0"
             }
         },
         "node_modules/import-local": {
             }
         },
         "node_modules/import-local": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
-            "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
+            "version": "3.2.0",
+            "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
+            "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "pkg-dir": "^4.2.0",
                 "resolve-cwd": "^3.0.0"
             "dependencies": {
                 "pkg-dir": "^4.2.0",
                 "resolve-cwd": "^3.0.0"
             "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
             "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
             "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.8.19"
             }
             "engines": {
                 "node": ">=0.8.19"
             }
             "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
             "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
             "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             }
             "engines": {
                 "node": ">=8"
             }
             "version": "1.0.6",
             "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
             "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
             "version": "1.0.6",
             "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
             "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+            "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
                 "once": "^1.3.0",
                 "wrappy": "1"
             "dependencies": {
                 "once": "^1.3.0",
                 "wrappy": "1"
             "version": "2.0.4",
             "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
             "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
             "version": "2.0.4",
             "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
             "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-            "dev": true
+            "dev": true,
+            "license": "ISC"
         },
         "node_modules/internal-slot": {
         },
         "node_modules/internal-slot": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
-            "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
+            "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "get-intrinsic": "^1.2.0",
-                "has": "^1.0.3",
-                "side-channel": "^1.0.4"
+                "es-errors": "^1.3.0",
+                "hasown": "^2.0.2",
+                "side-channel": "^1.1.0"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "version": "2.0.3",
             "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
             "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
             "version": "2.0.3",
             "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
             "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+            "license": "ISC",
             "engines": {
                 "node": ">=12"
             }
             "engines": {
                 "node": ">=12"
             }
             "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
             "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
             "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.10"
             }
             "engines": {
                 "node": ">= 0.10"
             }
             "version": "2.2.4",
             "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
             "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
             "version": "2.2.4",
             "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
             "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+            "license": "MIT",
             "dependencies": {
                 "loose-envify": "^1.0.0"
             }
         },
         "node_modules/ipaddr.js": {
             "dependencies": {
                 "loose-envify": "^1.0.0"
             }
         },
         "node_modules/ipaddr.js": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz",
-            "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==",
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
+            "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 10"
             }
         },
             "engines": {
                 "node": ">= 10"
             }
         },
-        "node_modules/is-arguments": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
-            "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+        "node_modules/is-array-buffer": {
+            "version": "3.0.5",
+            "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz",
+            "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "has-tostringtag": "^1.0.0"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.3",
+                "get-intrinsic": "^1.2.6"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/is-array-buffer": {
-            "version": "3.0.2",
-            "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
-            "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.2.0",
-                "is-typed-array": "^1.1.10"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
         "node_modules/is-arrayish": {
             "version": "0.2.1",
             "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
             "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
         "node_modules/is-arrayish": {
             "version": "0.2.1",
             "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
             "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/is-async-function": {
         },
         "node_modules/is-async-function": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
-            "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz",
+            "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-tostringtag": "^1.0.0"
+                "async-function": "^1.0.0",
+                "call-bound": "^1.0.3",
+                "get-proto": "^1.0.1",
+                "has-tostringtag": "^1.0.2",
+                "safe-regex-test": "^1.1.0"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/is-bigint": {
             }
         },
         "node_modules/is-bigint": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
-            "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz",
+            "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-bigints": "^1.0.1"
+                "has-bigints": "^1.0.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
             "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
             "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "binary-extensions": "^2.0.0"
             },
             "dependencies": {
                 "binary-extensions": "^2.0.0"
             },
             }
         },
         "node_modules/is-boolean-object": {
             }
         },
         "node_modules/is-boolean-object": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
-            "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+            "version": "1.2.2",
+            "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz",
+            "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "has-tostringtag": "^1.0.0"
+                "call-bound": "^1.0.3",
+                "has-tostringtag": "^1.0.2"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "version": "1.1.6",
             "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
             "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
             "version": "1.1.6",
             "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
             "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/is-callable": {
             "version": "1.2.7",
             "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
             "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
             "dev": true,
         },
         "node_modules/is-callable": {
             "version": "1.2.7",
             "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
             "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             }
         },
         "node_modules/is-core-module": {
             }
         },
         "node_modules/is-core-module": {
-            "version": "2.13.0",
-            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
-            "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
+            "version": "2.16.1",
+            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+            "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "hasown": "^2.0.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/is-data-view": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz",
+            "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has": "^1.0.3"
+                "call-bound": "^1.0.2",
+                "get-intrinsic": "^1.2.6",
+                "is-typed-array": "^1.1.13"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-date-object": {
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-date-object": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
-            "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz",
+            "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-tostringtag": "^1.0.0"
+                "call-bound": "^1.0.2",
+                "has-tostringtag": "^1.0.2"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
             "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
             "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
             "dev": true,
+            "license": "MIT",
             "bin": {
                 "is-docker": "cli.js"
             },
             "bin": {
                 "is-docker": "cli.js"
             },
             "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
             "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
             "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.10.0"
             }
         },
         "node_modules/is-finalizationregistry": {
             "engines": {
                 "node": ">=0.10.0"
             }
         },
         "node_modules/is-finalizationregistry": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz",
-            "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==",
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
+            "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2"
+                "call-bound": "^1.0.3"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
             "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
             "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             }
         },
             "engines": {
                 "node": ">=8"
             }
         },
-        "node_modules/is-generator-fn": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
-            "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
-            }
-        },
         "node_modules/is-generator-function": {
         "node_modules/is-generator-function": {
-            "version": "1.0.10",
-            "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
-            "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz",
+            "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-tostringtag": "^1.0.0"
+                "call-bound": "^1.0.3",
+                "get-proto": "^1.0.0",
+                "has-tostringtag": "^1.0.2",
+                "safe-regex-test": "^1.1.0"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
             "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
             "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "is-extglob": "^2.1.1"
             },
             "dependencies": {
                 "is-extglob": "^2.1.1"
             },
             }
         },
         "node_modules/is-map": {
             }
         },
         "node_modules/is-map": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
-            "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+            "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4"
+            },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-negative-zero": {
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-negative-zero": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
-            "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+            "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
             "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
             "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.12.0"
             }
         },
         "node_modules/is-number-object": {
             "engines": {
                 "node": ">=0.12.0"
             }
         },
         "node_modules/is-number-object": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
-            "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz",
+            "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-tostringtag": "^1.0.0"
+                "call-bound": "^1.0.3",
+                "has-tostringtag": "^1.0.2"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/is-path-inside": {
-            "version": "3.0.3",
-            "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-            "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
         "node_modules/is-plain-obj": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz",
             "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==",
             "dev": true,
         "node_modules/is-plain-obj": {
             "version": "3.0.0",
             "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz",
             "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=10"
             },
             "engines": {
                 "node": ">=10"
             },
             "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
             "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
             "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "isobject": "^3.0.1"
             },
             "dependencies": {
                 "isobject": "^3.0.1"
             },
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
             "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
             "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/is-regex": {
         },
         "node_modules/is-regex": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
-            "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz",
+            "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "has-tostringtag": "^1.0.0"
+                "call-bound": "^1.0.2",
+                "gopd": "^1.2.0",
+                "has-tostringtag": "^1.0.2",
+                "hasown": "^2.0.2"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/is-set": {
             }
         },
         "node_modules/is-set": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
-            "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+            "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4"
+            },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-shared-array-buffer": {
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-shared-array-buffer": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
-            "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz",
+            "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2"
+                "call-bound": "^1.0.3"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
             "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
             "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             },
             "engines": {
                 "node": ">=8"
             },
             }
         },
         "node_modules/is-string": {
             }
         },
         "node_modules/is-string": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
-            "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+            "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-tostringtag": "^1.0.0"
+                "call-bound": "^1.0.3",
+                "has-tostringtag": "^1.0.2"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/is-symbol": {
             }
         },
         "node_modules/is-symbol": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
-            "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz",
+            "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-symbols": "^1.0.2"
+                "call-bound": "^1.0.2",
+                "has-symbols": "^1.1.0",
+                "safe-regex-test": "^1.1.0"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/is-typed-array": {
             }
         },
         "node_modules/is-typed-array": {
-            "version": "1.1.12",
-            "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz",
-            "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
+            "version": "1.1.15",
+            "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+            "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "which-typed-array": "^1.1.11"
+                "which-typed-array": "^1.1.16"
             },
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             }
         },
         "node_modules/is-weakmap": {
             }
         },
         "node_modules/is-weakmap": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
-            "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+            "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4"
+            },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-weakref": {
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-weakref": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
-            "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz",
+            "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2"
+                "call-bound": "^1.0.3"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-weakset": {
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
         "node_modules/is-weakset": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
-            "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz",
+            "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.1.1"
+                "call-bound": "^1.0.3",
+                "get-intrinsic": "^1.2.6"
+            },
+            "engines": {
+                "node": ">= 0.4"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
             "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
             "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "is-docker": "^2.0.0"
             },
             "dependencies": {
                 "is-docker": "^2.0.0"
             },
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
             "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
             "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         "node_modules/isexe": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
             "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
         },
         "node_modules/isexe": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
             "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
-            "dev": true
+            "dev": true,
+            "license": "ISC"
         },
         "node_modules/isobject": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
             "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
             "dev": true,
         },
         "node_modules/isobject": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
             "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.10.0"
             }
             "engines": {
                 "node": ">=0.10.0"
             }
             "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
             "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
             "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
             "dev": true,
+            "license": "BSD-3-Clause",
             "engines": {
                 "node": ">=8"
             }
         },
             "engines": {
                 "node": ">=8"
             }
         },
-        "node_modules/istanbul-lib-instrument": {
-            "version": "6.0.2",
-            "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz",
-            "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==",
-            "dev": true,
-            "dependencies": {
-                "@babel/core": "^7.23.9",
-                "@babel/parser": "^7.23.9",
-                "@istanbuljs/schema": "^0.1.3",
-                "istanbul-lib-coverage": "^3.2.0",
-                "semver": "^7.5.4"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/istanbul-lib-instrument/node_modules/lru-cache": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-            "dev": true,
-            "dependencies": {
-                "yallist": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/istanbul-lib-instrument/node_modules/semver": {
-            "version": "7.6.0",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
-            "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
-            "dev": true,
-            "dependencies": {
-                "lru-cache": "^6.0.0"
-            },
-            "bin": {
-                "semver": "bin/semver.js"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/istanbul-lib-instrument/node_modules/yallist": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-            "dev": true
-        },
         "node_modules/istanbul-lib-report": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
             "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
             "dev": true,
         "node_modules/istanbul-lib-report": {
             "version": "3.0.1",
             "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
             "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
             "dev": true,
+            "license": "BSD-3-Clause",
             "dependencies": {
                 "istanbul-lib-coverage": "^3.0.0",
                 "make-dir": "^4.0.0",
             "dependencies": {
                 "istanbul-lib-coverage": "^3.0.0",
                 "make-dir": "^4.0.0",
                 "node": ">=10"
             }
         },
                 "node": ">=10"
             }
         },
-        "node_modules/istanbul-lib-report/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/istanbul-lib-report/node_modules/lru-cache": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-            "dev": true,
-            "dependencies": {
-                "yallist": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
         "node_modules/istanbul-lib-report/node_modules/make-dir": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
             "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
             "dev": true,
         "node_modules/istanbul-lib-report/node_modules/make-dir": {
             "version": "4.0.0",
             "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
             "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "semver": "^7.5.3"
             },
             "dependencies": {
                 "semver": "^7.5.3"
             },
             }
         },
         "node_modules/istanbul-lib-report/node_modules/semver": {
             }
         },
         "node_modules/istanbul-lib-report/node_modules/semver": {
-            "version": "7.6.0",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
-            "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
+            "version": "7.7.2",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+            "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "lru-cache": "^6.0.0"
-            },
+            "license": "ISC",
             "bin": {
                 "semver": "bin/semver.js"
             },
             "bin": {
                 "semver": "bin/semver.js"
             },
                 "node": ">=10"
             }
         },
                 "node": ">=10"
             }
         },
-        "node_modules/istanbul-lib-report/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-            "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/istanbul-lib-report/node_modules/yallist": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-            "dev": true
-        },
         "node_modules/istanbul-lib-source-maps": {
         "node_modules/istanbul-lib-source-maps": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
-            "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+            "version": "5.0.6",
+            "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz",
+            "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==",
             "dev": true,
             "dev": true,
+            "license": "BSD-3-Clause",
             "dependencies": {
             "dependencies": {
+                "@jridgewell/trace-mapping": "^0.3.23",
                 "debug": "^4.1.1",
                 "debug": "^4.1.1",
-                "istanbul-lib-coverage": "^3.0.0",
-                "source-map": "^0.6.1"
+                "istanbul-lib-coverage": "^3.0.0"
             },
             "engines": {
                 "node": ">=10"
             },
             "engines": {
                 "node": ">=10"
             "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
             "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
             "dev": true,
             "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
             "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
             "dev": true,
+            "license": "BSD-3-Clause",
             "dependencies": {
                 "html-escaper": "^2.0.0",
                 "istanbul-lib-report": "^3.0.0"
             "dependencies": {
                 "html-escaper": "^2.0.0",
                 "istanbul-lib-report": "^3.0.0"
             }
         },
         "node_modules/iterator.prototype": {
             }
         },
         "node_modules/iterator.prototype": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.1.tgz",
-            "integrity": "sha512-9E+nePc8C9cnQldmNl6bgpTY6zI4OPRZd97fhJ/iVZ1GifIUDVV5F6x1nEDqpe8KaMEZGT4xgrwKQDxXnjOIZQ==",
+            "version": "1.1.5",
+            "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
+            "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "define-properties": "^1.2.0",
-                "get-intrinsic": "^1.2.1",
-                "has-symbols": "^1.0.3",
-                "reflect.getprototypeof": "^1.0.3"
+                "define-data-property": "^1.1.4",
+                "es-object-atoms": "^1.0.0",
+                "get-intrinsic": "^1.2.6",
+                "get-proto": "^1.0.0",
+                "has-symbols": "^1.1.0",
+                "set-function-name": "^2.0.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/jest": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
-            "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
+        "node_modules/jackspeak": {
+            "version": "3.4.3",
+            "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+            "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
             "dev": true,
             "dev": true,
+            "license": "BlueOak-1.0.0",
             "dependencies": {
             "dependencies": {
-                "@jest/core": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "import-local": "^3.0.2",
-                "jest-cli": "^29.7.0"
-            },
-            "bin": {
-                "jest": "bin/jest.js"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "@isaacs/cliui": "^8.0.2"
             },
             },
-            "peerDependencies": {
-                "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
             },
             },
-            "peerDependenciesMeta": {
-                "node-notifier": {
-                    "optional": true
-                }
+            "optionalDependencies": {
+                "@pkgjs/parseargs": "^0.11.0"
             }
         },
             }
         },
-        "node_modules/jest-changed-files": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
-            "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
-            "dev": true,
-            "dependencies": {
-                "execa": "^5.0.0",
-                "jest-util": "^29.7.0",
-                "p-limit": "^3.1.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
-        "node_modules/jest-circus": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz",
-            "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
+        "node_modules/jest-worker": {
+            "version": "27.5.1",
+            "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+            "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/environment": "^29.7.0",
-                "@jest/expect": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/types": "^29.6.3",
                 "@types/node": "*",
                 "@types/node": "*",
-                "chalk": "^4.0.0",
-                "co": "^4.6.0",
-                "dedent": "^1.0.0",
-                "is-generator-fn": "^2.0.0",
-                "jest-each": "^29.7.0",
-                "jest-matcher-utils": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-runtime": "^29.7.0",
-                "jest-snapshot": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "p-limit": "^3.1.0",
-                "pretty-format": "^29.7.0",
-                "pure-rand": "^6.0.0",
-                "slash": "^3.0.0",
-                "stack-utils": "^2.0.3"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
-        "node_modules/jest-circus/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
+                "merge-stream": "^2.0.0",
+                "supports-color": "^8.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">= 10.13.0"
             }
         },
             }
         },
-        "node_modules/jest-circus/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/jest-worker/node_modules/supports-color": {
+            "version": "8.1.1",
+            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+            "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
+                "has-flag": "^4.0.0"
             },
             "engines": {
                 "node": ">=10"
             },
             "funding": {
             },
             "engines": {
                 "node": ">=10"
             },
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "url": "https://github.com/chalk/supports-color?sponsor=1"
             }
         },
             }
         },
-        "node_modules/jest-circus/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/jiti": {
+            "version": "1.21.7",
+            "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
+            "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
+            "license": "MIT",
+            "peer": true,
+            "bin": {
+                "jiti": "bin/jiti.js"
             }
         },
             }
         },
-        "node_modules/jest-circus/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
+        "node_modules/jquery": {
+            "version": "3.7.1",
+            "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
+            "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
+            "license": "MIT"
         },
         },
-        "node_modules/jest-circus/node_modules/has-flag": {
+        "node_modules/js-tokens": {
             "version": "4.0.0",
             "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
+            "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+            "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+            "license": "MIT"
         },
         },
-        "node_modules/jest-circus/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/js-yaml": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+            "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "argparse": "^2.0.1"
             },
             },
-            "engines": {
-                "node": ">=8"
+            "bin": {
+                "js-yaml": "bin/js-yaml.js"
             }
         },
             }
         },
-        "node_modules/jest-cli": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz",
-            "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
-            "dev": true,
-            "dependencies": {
-                "@jest/core": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "chalk": "^4.0.0",
-                "create-jest": "^29.7.0",
-                "exit": "^0.1.2",
-                "import-local": "^3.0.2",
-                "jest-config": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-validate": "^29.7.0",
-                "yargs": "^17.3.1"
-            },
-            "bin": {
-                "jest": "bin/jest.js"
+        "node_modules/jsdom": {
+            "version": "26.1.0",
+            "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz",
+            "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "cssstyle": "^4.2.1",
+                "data-urls": "^5.0.0",
+                "decimal.js": "^10.5.0",
+                "html-encoding-sniffer": "^4.0.0",
+                "http-proxy-agent": "^7.0.2",
+                "https-proxy-agent": "^7.0.6",
+                "is-potential-custom-element-name": "^1.0.1",
+                "nwsapi": "^2.2.16",
+                "parse5": "^7.2.1",
+                "rrweb-cssom": "^0.8.0",
+                "saxes": "^6.0.0",
+                "symbol-tree": "^3.2.4",
+                "tough-cookie": "^5.1.1",
+                "w3c-xmlserializer": "^5.0.0",
+                "webidl-conversions": "^7.0.0",
+                "whatwg-encoding": "^3.1.1",
+                "whatwg-mimetype": "^4.0.0",
+                "whatwg-url": "^14.1.1",
+                "ws": "^8.18.0",
+                "xml-name-validator": "^5.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=18"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+                "canvas": "^3.0.0"
             },
             "peerDependenciesMeta": {
             },
             "peerDependenciesMeta": {
-                "node-notifier": {
+                "canvas": {
                     "optional": true
                 }
             }
         },
                     "optional": true
                 }
             }
         },
-        "node_modules/jest-cli/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/jsesc": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+            "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
+            "license": "MIT",
+            "bin": {
+                "jsesc": "bin/jsesc"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/jest-cli/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/json-buffer": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+            "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-cli/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/json-parse-even-better-errors": {
+            "version": "2.3.1",
+            "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+            "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-cli/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
+        "node_modules/json-schema-traverse": {
+            "version": "0.4.1",
+            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+            "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/jest-cli/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/json-stable-stringify-without-jsonify": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+            "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-cli/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/json5": {
+            "version": "2.2.3",
+            "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+            "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
+            "license": "MIT",
+            "bin": {
+                "json5": "lib/cli.js"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/jest-config": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz",
-            "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
+        "node_modules/jsonfile": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+            "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/core": "^7.11.6",
-                "@jest/test-sequencer": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "babel-jest": "^29.7.0",
-                "chalk": "^4.0.0",
-                "ci-info": "^3.2.0",
-                "deepmerge": "^4.2.2",
-                "glob": "^7.1.3",
-                "graceful-fs": "^4.2.9",
-                "jest-circus": "^29.7.0",
-                "jest-environment-node": "^29.7.0",
-                "jest-get-type": "^29.6.3",
-                "jest-regex-util": "^29.6.3",
-                "jest-resolve": "^29.7.0",
-                "jest-runner": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-validate": "^29.7.0",
-                "micromatch": "^4.0.4",
-                "parse-json": "^5.2.0",
-                "pretty-format": "^29.7.0",
-                "slash": "^3.0.0",
-                "strip-json-comments": "^3.1.1"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            },
-            "peerDependencies": {
-                "@types/node": "*",
-                "ts-node": ">=9.0.0"
+                "universalify": "^2.0.0"
             },
             },
-            "peerDependenciesMeta": {
-                "@types/node": {
-                    "optional": true
-                },
-                "ts-node": {
-                    "optional": true
-                }
+            "optionalDependencies": {
+                "graceful-fs": "^4.1.6"
             }
         },
             }
         },
-        "node_modules/jest-config/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/jsx-ast-utils": {
+            "version": "3.3.5",
+            "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+            "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^2.0.1"
+                "array-includes": "^3.1.6",
+                "array.prototype.flat": "^1.3.1",
+                "object.assign": "^4.1.4",
+                "object.values": "^1.1.6"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">=4.0"
             }
         },
             }
         },
-        "node_modules/jest-config/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/junk": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
+            "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/jest-config/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/keyv": {
+            "version": "4.5.4",
+            "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+            "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
+                "json-buffer": "3.0.1"
             }
         },
             }
         },
-        "node_modules/jest-config/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-config/node_modules/deepmerge": {
-            "version": "4.3.1",
-            "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
-            "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+        "node_modules/kind-of": {
+            "version": "6.0.3",
+            "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+            "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=0.10.0"
             }
         },
             "engines": {
                 "node": ">=0.10.0"
             }
         },
-        "node_modules/jest-config/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/klona": {
+            "version": "2.0.6",
+            "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
+            "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 8"
             }
         },
             }
         },
-        "node_modules/jest-config/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-            "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
+        "node_modules/laravel-echo": {
+            "version": "1.19.0",
+            "resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.19.0.tgz",
+            "integrity": "sha512-o/X4XH8BIRwij66PSjtotZfM88Z8g/4P3gzxQf2BTcZBKmGqucvI5JYYLprR2OZQ9XlGsmJ2v+hDpPGEbXwUWw==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=10"
             }
         },
             }
         },
-        "node_modules/jest-diff": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
-            "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
+        "node_modules/laravel-mix": {
+            "version": "6.0.49",
+            "resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.49.tgz",
+            "integrity": "sha512-bBMFpFjp26XfijPvY5y9zGKud7VqlyOE0OWUcPo3vTBY5asw8LTjafAbee1dhfLz6PWNqDziz69CP78ELSpfKw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "chalk": "^4.0.0",
-                "diff-sequences": "^29.6.3",
-                "jest-get-type": "^29.6.3",
-                "pretty-format": "^29.7.0"
+                "@babel/core": "^7.15.8",
+                "@babel/plugin-proposal-object-rest-spread": "^7.15.6",
+                "@babel/plugin-syntax-dynamic-import": "^7.8.3",
+                "@babel/plugin-transform-runtime": "^7.15.8",
+                "@babel/preset-env": "^7.15.8",
+                "@babel/runtime": "^7.15.4",
+                "@types/babel__core": "^7.1.16",
+                "@types/clean-css": "^4.2.5",
+                "@types/imagemin-gifsicle": "^7.0.1",
+                "@types/imagemin-mozjpeg": "^8.0.1",
+                "@types/imagemin-optipng": "^5.2.1",
+                "@types/imagemin-svgo": "^8.0.0",
+                "autoprefixer": "^10.4.0",
+                "babel-loader": "^8.2.3",
+                "chalk": "^4.1.2",
+                "chokidar": "^3.5.2",
+                "clean-css": "^5.2.4",
+                "cli-table3": "^0.6.0",
+                "collect.js": "^4.28.5",
+                "commander": "^7.2.0",
+                "concat": "^1.0.3",
+                "css-loader": "^5.2.6",
+                "cssnano": "^5.0.8",
+                "dotenv": "^10.0.0",
+                "dotenv-expand": "^5.1.0",
+                "file-loader": "^6.2.0",
+                "fs-extra": "^10.0.0",
+                "glob": "^7.2.0",
+                "html-loader": "^1.3.2",
+                "imagemin": "^7.0.1",
+                "img-loader": "^4.0.0",
+                "lodash": "^4.17.21",
+                "md5": "^2.3.0",
+                "mini-css-extract-plugin": "^1.6.2",
+                "node-libs-browser": "^2.2.1",
+                "postcss-load-config": "^3.1.0",
+                "postcss-loader": "^6.2.0",
+                "semver": "^7.3.5",
+                "strip-ansi": "^6.0.0",
+                "style-loader": "^2.0.0",
+                "terser": "^5.9.0",
+                "terser-webpack-plugin": "^5.2.4",
+                "vue-style-loader": "^4.1.3",
+                "webpack": "^5.60.0",
+                "webpack-cli": "^4.9.1",
+                "webpack-dev-server": "^4.7.3",
+                "webpack-merge": "^5.8.0",
+                "webpack-notifier": "^1.14.1",
+                "webpackbar": "^5.0.0-3",
+                "yargs": "^17.2.1"
             },
             },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
-        "node_modules/jest-diff/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
+            "bin": {
+                "laravel-mix": "bin/cli.js",
+                "mix": "bin/cli.js"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=12.14.0"
             },
             },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+            "peerDependencies": {
+                "@babel/core": "^7.15.8",
+                "@babel/plugin-proposal-object-rest-spread": "^7.15.6",
+                "@babel/plugin-syntax-dynamic-import": "^7.8.3",
+                "@babel/plugin-transform-runtime": "^7.15.8",
+                "@babel/preset-env": "^7.15.8",
+                "postcss": "^8.3.11",
+                "webpack": "^5.60.0",
+                "webpack-cli": "^4.9.1"
             }
         },
             }
         },
-        "node_modules/jest-diff/node_modules/chalk": {
+        "node_modules/laravel-mix/node_modules/chalk": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
             "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
             "dev": true,
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
             "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
             "dev": true,
+            "license": "MIT",
             "dependencies": {
                 "ansi-styles": "^4.1.0",
                 "supports-color": "^7.1.0"
             "dependencies": {
                 "ansi-styles": "^4.1.0",
                 "supports-color": "^7.1.0"
                 "url": "https://github.com/chalk/chalk?sponsor=1"
             }
         },
                 "url": "https://github.com/chalk/chalk?sponsor=1"
             }
         },
-        "node_modules/jest-diff/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/laravel-mix/node_modules/semver": {
+            "version": "7.7.2",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+            "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
+            "license": "ISC",
+            "bin": {
+                "semver": "bin/semver.js"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/jest-diff/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-diff/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
+                "node": ">=10"
             }
         },
             }
         },
-        "node_modules/jest-diff/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/laravel-vite-plugin": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.3.0.tgz",
+            "integrity": "sha512-P5qyG56YbYxM8OuYmK2OkhcKe0AksNVJUjq9LUZ5tOekU9fBn9LujYyctI4t9XoLjuMvHJXXpCoPntY1oKltuA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "picocolors": "^1.0.0",
+                "vite-plugin-full-reload": "^1.1.0"
+            },
+            "bin": {
+                "clean-orphaned-assets": "bin/clean.js"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+            },
+            "peerDependencies": {
+                "vite": "^5.0.0 || ^6.0.0"
             }
         },
             }
         },
-        "node_modules/jest-docblock": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz",
-            "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
+        "node_modules/launch-editor": {
+            "version": "2.10.0",
+            "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.10.0.tgz",
+            "integrity": "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "detect-newline": "^3.0.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "picocolors": "^1.0.0",
+                "shell-quote": "^1.8.1"
             }
         },
             }
         },
-        "node_modules/jest-each": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz",
-            "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
+        "node_modules/levn": {
+            "version": "0.4.1",
+            "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+            "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/types": "^29.6.3",
-                "chalk": "^4.0.0",
-                "jest-get-type": "^29.6.3",
-                "jest-util": "^29.7.0",
-                "pretty-format": "^29.7.0"
+                "prelude-ls": "^1.2.1",
+                "type-check": "~0.4.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">= 0.8.0"
             }
         },
             }
         },
-        "node_modules/jest-each/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
+        "node_modules/lie": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
+            "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "immediate": "~3.0.5"
             }
         },
             }
         },
-        "node_modules/jest-each/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/lilconfig": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+            "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
+            "license": "MIT",
             "engines": {
                 "node": ">=10"
             "engines": {
                 "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
             }
         },
             }
         },
-        "node_modules/jest-each/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/lines-and-columns": {
+            "version": "1.2.4",
+            "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+            "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/jest-each/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
+            "license": "MIT"
         },
         },
-        "node_modules/jest-each/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/loader-runner": {
+            "version": "4.3.0",
+            "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
+            "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=6.11.5"
             }
         },
             }
         },
-        "node_modules/jest-each/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/loader-utils": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+            "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "big.js": "^5.2.2",
+                "emojis-list": "^3.0.0",
+                "json5": "^2.1.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=8.9.0"
             }
         },
             }
         },
-        "node_modules/jest-environment-jsdom": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz",
-            "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==",
-            "dev": true,
+        "node_modules/localforage": {
+            "version": "1.10.0",
+            "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
+            "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
-                "@jest/environment": "^29.7.0",
-                "@jest/fake-timers": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/jsdom": "^20.0.0",
-                "@types/node": "*",
-                "jest-mock": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jsdom": "^20.0.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            },
-            "peerDependencies": {
-                "canvas": "^2.5.0"
-            },
-            "peerDependenciesMeta": {
-                "canvas": {
-                    "optional": true
-                }
+                "lie": "3.1.1"
             }
         },
             }
         },
-        "node_modules/jest-environment-node": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
-            "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
+        "node_modules/locate-path": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+            "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/environment": "^29.7.0",
-                "@jest/fake-timers": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "jest-mock": "^29.7.0",
-                "jest-util": "^29.7.0"
+                "p-locate": "^5.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jest-get-type": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
-            "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
-            "dev": true,
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
+        "node_modules/lodash": {
+            "version": "4.17.21",
+            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+            "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+            "license": "MIT"
         },
         },
-        "node_modules/jest-haste-map": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
-            "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
-            "dev": true,
-            "dependencies": {
-                "@jest/types": "^29.6.3",
-                "@types/graceful-fs": "^4.1.3",
-                "@types/node": "*",
-                "anymatch": "^3.0.3",
-                "fb-watchman": "^2.0.0",
-                "graceful-fs": "^4.2.9",
-                "jest-regex-util": "^29.6.3",
-                "jest-util": "^29.7.0",
-                "jest-worker": "^29.7.0",
-                "micromatch": "^4.0.4",
-                "walker": "^1.0.8"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            },
-            "optionalDependencies": {
-                "fsevents": "^2.3.2"
-            }
+        "node_modules/lodash-es": {
+            "version": "4.17.21",
+            "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
+            "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
+            "license": "MIT"
         },
         },
-        "node_modules/jest-haste-map/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/lodash.debounce": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+            "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-haste-map/node_modules/jest-worker": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
-            "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+        "node_modules/lodash.memoize": {
+            "version": "4.1.2",
+            "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+            "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@types/node": "*",
-                "jest-util": "^29.7.0",
-                "merge-stream": "^2.0.0",
-                "supports-color": "^8.0.0"
+            "license": "MIT"
+        },
+        "node_modules/lodash.merge": {
+            "version": "4.6.2",
+            "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+            "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/lodash.uniq": {
+            "version": "4.5.0",
+            "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+            "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "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==",
+            "license": "MIT",
+            "dependencies": {
+                "js-tokens": "^3.0.0 || ^4.0.0"
             },
             },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+            "bin": {
+                "loose-envify": "cli.js"
             }
         },
             }
         },
-        "node_modules/jest-haste-map/node_modules/supports-color": {
-            "version": "8.1.1",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-            "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+        "node_modules/loupe": {
+            "version": "3.1.4",
+            "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.4.tgz",
+            "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/lower-case": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
+            "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/supports-color?sponsor=1"
+                "tslib": "^2.0.3"
             }
         },
             }
         },
-        "node_modules/jest-leak-detector": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
-            "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
+        "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==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "jest-get-type": "^29.6.3",
-                "pretty-format": "^29.7.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "yallist": "^3.0.2"
+            }
+        },
+        "node_modules/lz-string": {
+            "version": "1.5.0",
+            "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
+            "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+            "dev": true,
+            "license": "MIT",
+            "peer": true,
+            "bin": {
+                "lz-string": "bin/bin.js"
             }
         },
             }
         },
-        "node_modules/jest-matcher-utils": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
-            "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
+        "node_modules/magic-string": {
+            "version": "0.30.17",
+            "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+            "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "chalk": "^4.0.0",
-                "jest-diff": "^29.7.0",
-                "jest-get-type": "^29.6.3",
-                "pretty-format": "^29.7.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "@jridgewell/sourcemap-codec": "^1.5.0"
             }
         },
             }
         },
-        "node_modules/jest-matcher-utils/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/magicast": {
+            "version": "0.3.5",
+            "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz",
+            "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "@babel/parser": "^7.25.4",
+                "@babel/types": "^7.25.4",
+                "source-map-js": "^1.2.0"
             }
         },
             }
         },
-        "node_modules/jest-matcher-utils/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/make-dir": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+            "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
+                "semver": "^6.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": ">=8"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jest-matcher-utils/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-            "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
+        "node_modules/math-intrinsics": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+            "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/jest-matcher-utils/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-matcher-utils/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/md5": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
+            "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=8"
+            "license": "BSD-3-Clause",
+            "dependencies": {
+                "charenc": "0.0.2",
+                "crypt": "0.0.2",
+                "is-buffer": "~1.1.6"
             }
         },
             }
         },
-        "node_modules/jest-matcher-utils/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/md5.js": {
+            "version": "1.3.5",
+            "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+            "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
+                "hash-base": "^3.0.0",
+                "inherits": "^2.0.1",
+                "safe-buffer": "^5.1.2"
             }
         },
             }
         },
-        "node_modules/jest-message-util": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
-            "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
+        "node_modules/mdn-data": {
+            "version": "2.0.14",
+            "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
+            "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@babel/code-frame": "^7.12.13",
-                "@jest/types": "^29.6.3",
-                "@types/stack-utils": "^2.0.0",
-                "chalk": "^4.0.0",
-                "graceful-fs": "^4.2.9",
-                "micromatch": "^4.0.4",
-                "pretty-format": "^29.7.0",
-                "slash": "^3.0.0",
-                "stack-utils": "^2.0.3"
-            },
+            "license": "CC0-1.0"
+        },
+        "node_modules/media-typer": {
+            "version": "0.3.0",
+            "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+            "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/jest-message-util/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/memfs": {
+            "version": "3.5.3",
+            "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz",
+            "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==",
             "dev": true,
             "dev": true,
+            "license": "Unlicense",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^2.0.1"
+                "fs-monkey": "^1.0.4"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">= 4.0.0"
             }
         },
             }
         },
-        "node_modules/jest-message-util/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/merge-descriptors": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+            "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
+            "license": "MIT",
             "funding": {
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jest-message-util/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/merge-stream": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+            "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
+            "license": "MIT"
+        },
+        "node_modules/merge2": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+            "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">= 8"
             }
         },
             }
         },
-        "node_modules/jest-message-util/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-message-util/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/methods": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+            "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/jest-message-util/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/micromatch": {
+            "version": "4.0.8",
+            "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+            "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "braces": "^3.0.3",
+                "picomatch": "^2.3.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=8.6"
             }
         },
             }
         },
-        "node_modules/jest-mock": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
-            "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
+        "node_modules/miller-rabin": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+            "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "jest-util": "^29.7.0"
+                "bn.js": "^4.0.0",
+                "brorand": "^1.0.1"
             },
             },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+            "bin": {
+                "miller-rabin": "bin/miller-rabin"
             }
         },
             }
         },
-        "node_modules/jest-pnp-resolver": {
-            "version": "1.2.3",
-            "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
-            "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+        "node_modules/miller-rabin/node_modules/bn.js": {
+            "version": "4.12.2",
+            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
+            "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=6"
-            },
-            "peerDependencies": {
-                "jest-resolve": "*"
-            },
-            "peerDependenciesMeta": {
-                "jest-resolve": {
-                    "optional": true
-                }
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-regex-util": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
-            "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
+        "node_modules/mime": {
+            "version": "1.6.0",
+            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "bin": {
+                "mime": "cli.js"
+            },
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=4"
             }
         },
             }
         },
-        "node_modules/jest-resolve": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz",
-            "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
+        "node_modules/mime-db": {
+            "version": "1.52.0",
+            "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+            "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "chalk": "^4.0.0",
-                "graceful-fs": "^4.2.9",
-                "jest-haste-map": "^29.7.0",
-                "jest-pnp-resolver": "^1.2.2",
-                "jest-util": "^29.7.0",
-                "jest-validate": "^29.7.0",
-                "resolve": "^1.20.0",
-                "resolve.exports": "^2.0.0",
-                "slash": "^3.0.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/jest-resolve-dependencies": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
-            "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
+        "node_modules/mime-types": {
+            "version": "2.1.35",
+            "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+            "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "jest-regex-util": "^29.6.3",
-                "jest-snapshot": "^29.7.0"
+                "mime-db": "1.52.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/jest-resolve/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/mimic-fn": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+            "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/jest-resolve/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/min-indent": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+            "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
+        },
+        "node_modules/mini-css-extract-plugin": {
+            "version": "1.6.2",
+            "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz",
+            "integrity": "sha512-WhDvO3SjGm40oV5y26GjMJYjd2UMqrLAGKy5YS2/3QKJy2F7jgynuHTir/tgUUOiNQu5saXHdc8reo7YuhhT4Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
+                "loader-utils": "^2.0.0",
+                "schema-utils": "^3.0.0",
+                "webpack-sources": "^1.1.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": ">= 10.13.0"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
+            },
+            "peerDependencies": {
+                "webpack": "^4.4.0 || ^5.0.0"
             }
         },
             }
         },
-        "node_modules/jest-resolve/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/mini-css-extract-plugin/node_modules/schema-utils": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+            "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "@types/json-schema": "^7.0.8",
+                "ajv": "^6.12.5",
+                "ajv-keywords": "^3.5.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">= 10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
             }
         },
             }
         },
-        "node_modules/jest-resolve/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-resolve/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/mini-svg-data-uri": {
+            "version": "1.4.4",
+            "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
+            "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=8"
+            "license": "MIT",
+            "bin": {
+                "mini-svg-data-uri": "cli.js"
             }
         },
             }
         },
-        "node_modules/jest-resolve/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/minimalistic-assert": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+            "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
+            "license": "ISC"
         },
         },
-        "node_modules/jest-runner": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz",
-            "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
+        "node_modules/minimalistic-crypto-utils": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+            "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@jest/console": "^29.7.0",
-                "@jest/environment": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "emittery": "^0.13.1",
-                "graceful-fs": "^4.2.9",
-                "jest-docblock": "^29.7.0",
-                "jest-environment-node": "^29.7.0",
-                "jest-haste-map": "^29.7.0",
-                "jest-leak-detector": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-resolve": "^29.7.0",
-                "jest-runtime": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-watcher": "^29.7.0",
-                "jest-worker": "^29.7.0",
-                "p-limit": "^3.1.0",
-                "source-map-support": "0.5.13"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
-        },
-        "node_modules/jest-runner/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+            "license": "MIT"
+        },
+        "node_modules/minimatch": {
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+            "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^2.0.1"
+                "brace-expansion": "^1.1.7"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": "*"
             }
         },
             }
         },
-        "node_modules/jest-runner/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/minimist": {
+            "version": "1.2.8",
+            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+            "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
+            "license": "MIT",
             "funding": {
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/jest-runner/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/minipass": {
+            "version": "7.1.2",
+            "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+            "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
+            "license": "ISC",
             "engines": {
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">=16 || 14 >=14.17"
             }
         },
             }
         },
-        "node_modules/jest-runner/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-runner/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
+        "node_modules/moment": {
+            "version": "2.30.1",
+            "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
+            "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": "*"
             }
         },
             }
         },
-        "node_modules/jest-runner/node_modules/jest-worker": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
-            "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+        "node_modules/ms": {
+            "version": "2.1.3",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+            "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@types/node": "*",
-                "jest-util": "^29.7.0",
-                "merge-stream": "^2.0.0",
-                "supports-color": "^8.0.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-runner/node_modules/jest-worker/node_modules/supports-color": {
-            "version": "8.1.1",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-            "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+        "node_modules/multicast-dns": {
+            "version": "7.2.5",
+            "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",
+            "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=10"
+                "dns-packet": "^5.2.2",
+                "thunky": "^1.0.2"
             },
             },
-            "funding": {
-                "url": "https://github.com/chalk/supports-color?sponsor=1"
+            "bin": {
+                "multicast-dns": "cli.js"
             }
         },
             }
         },
-        "node_modules/jest-runner/node_modules/source-map-support": {
-            "version": "0.5.13",
-            "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
-            "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+        "node_modules/mz": {
+            "version": "2.7.0",
+            "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+            "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "buffer-from": "^1.0.0",
-                "source-map": "^0.6.0"
+                "any-promise": "^1.0.0",
+                "object-assign": "^4.0.1",
+                "thenify-all": "^1.0.0"
             }
         },
             }
         },
-        "node_modules/jest-runner/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/nanoid": {
+            "version": "3.3.11",
+            "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+            "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/ai"
+                }
+            ],
+            "license": "MIT",
+            "bin": {
+                "nanoid": "bin/nanoid.cjs"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
             }
         },
             }
         },
-        "node_modules/jest-runtime": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz",
-            "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
+        "node_modules/natural-compare": {
+            "version": "1.4.0",
+            "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+            "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@jest/environment": "^29.7.0",
-                "@jest/fake-timers": "^29.7.0",
-                "@jest/globals": "^29.7.0",
-                "@jest/source-map": "^29.6.3",
-                "@jest/test-result": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "cjs-module-lexer": "^1.0.0",
-                "collect-v8-coverage": "^1.0.0",
-                "glob": "^7.1.3",
-                "graceful-fs": "^4.2.9",
-                "jest-haste-map": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-mock": "^29.7.0",
-                "jest-regex-util": "^29.6.3",
-                "jest-resolve": "^29.7.0",
-                "jest-snapshot": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "slash": "^3.0.0",
-                "strip-bom": "^4.0.0"
-            },
-            "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-runtime/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/negotiator": {
+            "version": "0.6.4",
+            "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
+            "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/jest-runtime/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/neo-async": {
+            "version": "2.6.2",
+            "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+            "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-runtime/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/no-case": {
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
+            "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
+                "lower-case": "^2.0.2",
+                "tslib": "^2.0.3"
             }
         },
             }
         },
-        "node_modules/jest-runtime/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
+        "node_modules/node-addon-api": {
+            "version": "7.1.1",
+            "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+            "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+            "dev": true,
+            "license": "MIT",
+            "optional": true
         },
         },
-        "node_modules/jest-runtime/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/node-forge": {
+            "version": "1.3.1",
+            "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+            "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
             "dev": true,
             "dev": true,
+            "license": "(BSD-3-Clause OR GPL-2.0)",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 6.13.0"
             }
         },
             }
         },
-        "node_modules/jest-runtime/node_modules/strip-bom": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
-            "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+        "node_modules/node-libs-browser": {
+            "version": "2.2.1",
+            "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
+            "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=8"
+            "license": "MIT",
+            "dependencies": {
+                "assert": "^1.1.1",
+                "browserify-zlib": "^0.2.0",
+                "buffer": "^4.3.0",
+                "console-browserify": "^1.1.0",
+                "constants-browserify": "^1.0.0",
+                "crypto-browserify": "^3.11.0",
+                "domain-browser": "^1.1.1",
+                "events": "^3.0.0",
+                "https-browserify": "^1.0.0",
+                "os-browserify": "^0.3.0",
+                "path-browserify": "0.0.1",
+                "process": "^0.11.10",
+                "punycode": "^1.2.4",
+                "querystring-es3": "^0.2.0",
+                "readable-stream": "^2.3.3",
+                "stream-browserify": "^2.0.1",
+                "stream-http": "^2.7.2",
+                "string_decoder": "^1.0.0",
+                "timers-browserify": "^2.0.4",
+                "tty-browserify": "0.0.0",
+                "url": "^0.11.0",
+                "util": "^0.11.0",
+                "vm-browserify": "^1.0.1"
             }
         },
             }
         },
-        "node_modules/jest-runtime/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/node-notifier": {
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-9.0.1.tgz",
+            "integrity": "sha512-fPNFIp2hF/Dq7qLDzSg4vZ0J4e9v60gJR+Qx7RbjbWqzPDdEqeVpEx5CFeDAELIl+A/woaaNn1fQ5nEVerMxJg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "growly": "^1.3.0",
+                "is-wsl": "^2.2.0",
+                "semver": "^7.3.2",
+                "shellwords": "^0.1.1",
+                "uuid": "^8.3.0",
+                "which": "^2.0.2"
+            }
+        },
+        "node_modules/node-notifier/node_modules/semver": {
+            "version": "7.7.2",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+            "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+            "dev": true,
+            "license": "ISC",
+            "bin": {
+                "semver": "bin/semver.js"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=10"
             }
         },
             }
         },
-        "node_modules/jest-snapshot": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
-            "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
+        "node_modules/node-releases": {
+            "version": "2.0.19",
+            "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+            "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@babel/core": "^7.11.6",
-                "@babel/generator": "^7.7.2",
-                "@babel/plugin-syntax-jsx": "^7.7.2",
-                "@babel/plugin-syntax-typescript": "^7.7.2",
-                "@babel/types": "^7.3.3",
-                "@jest/expect-utils": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "babel-preset-current-node-syntax": "^1.0.0",
-                "chalk": "^4.0.0",
-                "expect": "^29.7.0",
-                "graceful-fs": "^4.2.9",
-                "jest-diff": "^29.7.0",
-                "jest-get-type": "^29.6.3",
-                "jest-matcher-utils": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "natural-compare": "^1.4.0",
-                "pretty-format": "^29.7.0",
-                "semver": "^7.5.3"
-            },
+            "license": "MIT"
+        },
+        "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==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "node_modules/jest-snapshot/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "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,
             "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "node_modules/jest-snapshot/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/normalize-url": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
+            "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
+            "license": "MIT",
             "engines": {
                 "node": ">=10"
             },
             "funding": {
             "engines": {
                 "node": ">=10"
             },
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jest-snapshot/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/npm-run-path": {
+            "version": "4.0.1",
+            "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+            "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "path-key": "^3.0.0"
             },
             },
-            "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/jest-snapshot/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-snapshot/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
             "engines": {
                 "node": ">=8"
             }
         },
             "engines": {
                 "node": ">=8"
             }
         },
-        "node_modules/jest-snapshot/node_modules/lru-cache": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+        "node_modules/nth-check": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
             "dev": true,
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
             "dependencies": {
-                "yallist": "^4.0.0"
+                "boolbase": "^1.0.0"
             },
             },
-            "engines": {
-                "node": ">=10"
+            "funding": {
+                "url": "https://github.com/fb55/nth-check?sponsor=1"
             }
         },
             }
         },
-        "node_modules/jest-snapshot/node_modules/semver": {
-            "version": "7.6.0",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
-            "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
-            "dev": true,
-            "dependencies": {
-                "lru-cache": "^6.0.0"
-            },
-            "bin": {
-                "semver": "bin/semver.js"
-            },
+        "node_modules/numeral": {
+            "version": "2.0.6",
+            "resolved": "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz",
+            "integrity": "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=10"
+                "node": "*"
             }
         },
             }
         },
-        "node_modules/jest-snapshot/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/nwsapi": {
+            "version": "2.2.20",
+            "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz",
+            "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
+            "license": "MIT"
+        },
+        "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==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "node_modules/jest-snapshot/node_modules/yallist": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-            "dev": true
-        },
-        "node_modules/jest-util": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
-            "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+        "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==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "ci-info": "^3.2.0",
-                "graceful-fs": "^4.2.9",
-                "picomatch": "^2.2.3"
-            },
+            "license": "MIT",
+            "peer": true,
             "engines": {
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">= 6"
             }
         },
             }
         },
-        "node_modules/jest-util/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
+        "node_modules/object-inspect": {
+            "version": "1.13.4",
+            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+            "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.4"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/jest-util/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/object-keys": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+            "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/jest-util/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/object.assign": {
+            "version": "4.1.7",
+            "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz",
+            "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.3",
+                "define-properties": "^1.2.1",
+                "es-object-atoms": "^1.0.0",
+                "has-symbols": "^1.1.0",
+                "object-keys": "^1.1.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/jest-util/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-util/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/object.entries": {
+            "version": "1.1.9",
+            "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
+            "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.4",
+                "define-properties": "^1.2.1",
+                "es-object-atoms": "^1.1.1"
+            },
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/jest-util/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/object.fromentries": {
+            "version": "2.0.8",
+            "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+            "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "call-bind": "^1.0.7",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.2",
+                "es-object-atoms": "^1.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/jest-validate": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz",
-            "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
+        "node_modules/object.groupby": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+            "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/types": "^29.6.3",
-                "camelcase": "^6.2.0",
-                "chalk": "^4.0.0",
-                "jest-get-type": "^29.6.3",
-                "leven": "^3.1.0",
-                "pretty-format": "^29.7.0"
+                "call-bind": "^1.0.7",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.2"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/jest-validate/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/object.values": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+            "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^2.0.1"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.3",
+                "define-properties": "^1.2.1",
+                "es-object-atoms": "^1.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.4"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/jest-validate/node_modules/camelcase": {
-            "version": "6.3.0",
-            "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
-            "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+        "node_modules/obuf": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
+            "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/jest-validate/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/on-finished": {
+            "version": "2.4.1",
+            "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+            "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
+                "ee-first": "1.1.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "node": ">= 0.8"
             }
         },
             }
         },
-        "node_modules/jest-validate/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/on-headers": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+            "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">= 0.8"
             }
         },
             }
         },
-        "node_modules/jest-validate/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
+        "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==",
+            "dev": true,
+            "license": "ISC",
+            "dependencies": {
+                "wrappy": "1"
+            }
         },
         },
-        "node_modules/jest-validate/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/onetime": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+            "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "mimic-fn": "^2.1.0"
+            },
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jest-validate/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/open": {
+            "version": "8.4.2",
+            "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+            "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "define-lazy-prop": "^2.0.0",
+                "is-docker": "^2.1.1",
+                "is-wsl": "^2.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
+        },
+        "node_modules/openseadragon": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/openseadragon/-/openseadragon-4.1.1.tgz",
+            "integrity": "sha512-owU9gsasAcobLN+LM8lN58Xc2VDSDotY9mkrwS/NB6g9KX/PcusV4RZvhHng2RF/Q0pMziwldf62glwXoGnuzg==",
+            "license": "BSD-3-Clause",
+            "funding": {
+                "url": "https://opencollective.com/openseadragon"
             }
         },
             }
         },
-        "node_modules/jest-watcher": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz",
-            "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
+        "node_modules/optionator": {
+            "version": "0.9.4",
+            "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+            "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/test-result": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "ansi-escapes": "^4.2.1",
-                "chalk": "^4.0.0",
-                "emittery": "^0.13.1",
-                "jest-util": "^29.7.0",
-                "string-length": "^4.0.1"
+                "deep-is": "^0.1.3",
+                "fast-levenshtein": "^2.0.6",
+                "levn": "^0.4.1",
+                "prelude-ls": "^1.2.1",
+                "type-check": "^0.4.0",
+                "word-wrap": "^1.2.5"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">= 0.8.0"
             }
         },
             }
         },
-        "node_modules/jest-watcher/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+        "node_modules/os-browserify": {
+            "version": "0.3.0",
+            "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+            "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/own-keys": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
+            "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-convert": "^2.0.1"
+                "get-intrinsic": "^1.2.6",
+                "object-keys": "^1.1.1",
+                "safe-push-apply": "^1.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.4"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/jest-watcher/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/p-limit": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+            "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
+                "yocto-queue": "^0.1.0"
             },
             "engines": {
                 "node": ">=10"
             },
             "funding": {
             },
             "engines": {
                 "node": ">=10"
             },
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jest-watcher/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/p-locate": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+            "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "p-limit": "^3.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jest-watcher/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/jest-watcher/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/p-pipe": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz",
+            "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
                 "node": ">=8"
             "engines": {
                 "node": ">=8"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jest-watcher/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/p-retry": {
+            "version": "4.6.2",
+            "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
+            "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "@types/retry": "0.12.0",
+                "retry": "^0.13.1"
             },
             "engines": {
                 "node": ">=8"
             }
         },
             },
             "engines": {
                 "node": ">=8"
             }
         },
-        "node_modules/jest-worker": {
-            "version": "27.5.1",
-            "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
-            "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+        "node_modules/p-try": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+            "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=6"
+            }
+        },
+        "node_modules/package-json-from-dist": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+            "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
             "dev": true,
             "dev": true,
+            "license": "BlueOak-1.0.0"
+        },
+        "node_modules/pako": {
+            "version": "1.0.11",
+            "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+            "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+            "dev": true,
+            "license": "(MIT AND Zlib)"
+        },
+        "node_modules/param-case": {
+            "version": "3.0.4",
+            "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
+            "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@types/node": "*",
-                "merge-stream": "^2.0.0",
-                "supports-color": "^8.0.0"
+                "dot-case": "^3.0.4",
+                "tslib": "^2.0.3"
+            }
+        },
+        "node_modules/parent-module": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+            "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "callsites": "^3.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 10.13.0"
+                "node": ">=6"
             }
         },
             }
         },
-        "node_modules/jest-worker/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/parse-asn1": {
+            "version": "5.1.7",
+            "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz",
+            "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
+            "dependencies": {
+                "asn1.js": "^4.10.1",
+                "browserify-aes": "^1.2.0",
+                "evp_bytestokey": "^1.0.3",
+                "hash-base": "~3.0",
+                "pbkdf2": "^3.1.2",
+                "safe-buffer": "^5.2.1"
+            },
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.10"
             }
         },
             }
         },
-        "node_modules/jest-worker/node_modules/supports-color": {
-            "version": "8.1.1",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-            "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+        "node_modules/parse-json": {
+            "version": "5.2.0",
+            "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+            "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "@babel/code-frame": "^7.0.0",
+                "error-ex": "^1.3.1",
+                "json-parse-even-better-errors": "^2.3.0",
+                "lines-and-columns": "^1.1.6"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": ">=8"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/supports-color?sponsor=1"
-            }
-        },
-        "node_modules/jiti": {
-            "version": "1.19.3",
-            "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.3.tgz",
-            "integrity": "sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==",
-            "dev": true,
-            "bin": {
-                "jiti": "bin/jiti.js"
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/jquery": {
-            "version": "3.7.1",
-            "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
-            "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
-        },
-        "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/js-yaml": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-            "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+        "node_modules/parse5": {
+            "version": "7.3.0",
+            "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+            "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "argparse": "^2.0.1"
+                "entities": "^6.0.0"
             },
             },
-            "bin": {
-                "js-yaml": "bin/js-yaml.js"
+            "funding": {
+                "url": "https://github.com/inikulin/parse5?sponsor=1"
             }
         },
             }
         },
-        "node_modules/jsdom": {
-            "version": "20.0.3",
-            "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz",
-            "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==",
-            "dev": true,
-            "dependencies": {
-                "abab": "^2.0.6",
-                "acorn": "^8.8.1",
-                "acorn-globals": "^7.0.0",
-                "cssom": "^0.5.0",
-                "cssstyle": "^2.3.0",
-                "data-urls": "^3.0.2",
-                "decimal.js": "^10.4.2",
-                "domexception": "^4.0.0",
-                "escodegen": "^2.0.0",
-                "form-data": "^4.0.0",
-                "html-encoding-sniffer": "^3.0.0",
-                "http-proxy-agent": "^5.0.0",
-                "https-proxy-agent": "^5.0.1",
-                "is-potential-custom-element-name": "^1.0.1",
-                "nwsapi": "^2.2.2",
-                "parse5": "^7.1.1",
-                "saxes": "^6.0.0",
-                "symbol-tree": "^3.2.4",
-                "tough-cookie": "^4.1.2",
-                "w3c-xmlserializer": "^4.0.0",
-                "webidl-conversions": "^7.0.0",
-                "whatwg-encoding": "^2.0.0",
-                "whatwg-mimetype": "^3.0.0",
-                "whatwg-url": "^11.0.0",
-                "ws": "^8.11.0",
-                "xml-name-validator": "^4.0.0"
-            },
+        "node_modules/parse5/node_modules/entities": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+            "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+            "dev": true,
+            "license": "BSD-2-Clause",
             "engines": {
             "engines": {
-                "node": ">=14"
-            },
-            "peerDependencies": {
-                "canvas": "^2.5.0"
+                "node": ">=0.12"
             },
             },
-            "peerDependenciesMeta": {
-                "canvas": {
-                    "optional": true
-                }
+            "funding": {
+                "url": "https://github.com/fb55/entities?sponsor=1"
             }
         },
             }
         },
-        "node_modules/jsesc": {
-            "version": "2.5.2",
-            "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
-            "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+        "node_modules/parseurl": {
+            "version": "1.3.3",
+            "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+            "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
             "dev": true,
             "dev": true,
-            "bin": {
-                "jsesc": "bin/jsesc"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=4"
+                "node": ">= 0.8"
             }
         },
             }
         },
-        "node_modules/json-buffer": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
-            "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
-            "dev": true
+        "node_modules/pascal-case": {
+            "version": "3.1.2",
+            "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
+            "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "no-case": "^3.0.4",
+                "tslib": "^2.0.3"
+            }
         },
         },
-        "node_modules/json-parse-even-better-errors": {
-            "version": "2.3.1",
-            "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
-            "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
-            "dev": true
+        "node_modules/path-browserify": {
+            "version": "0.0.1",
+            "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
+            "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/json-schema-traverse": {
-            "version": "0.4.1",
-            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-            "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-            "dev": true
+        "node_modules/path-exists": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+            "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=8"
+            }
         },
         },
-        "node_modules/json-stable-stringify-without-jsonify": {
+        "node_modules/path-is-absolute": {
             "version": "1.0.1",
             "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-            "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
-            "dev": true
+            "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+            "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
         },
         },
-        "node_modules/json5": {
-            "version": "2.2.3",
-            "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
-            "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+        "node_modules/path-key": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+            "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
             "dev": true,
             "dev": true,
-            "bin": {
-                "json5": "lib/cli.js"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=6"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/jsonfile": {
-            "version": "6.1.0",
-            "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
-            "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+        "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==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/path-scurry": {
+            "version": "1.11.1",
+            "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+            "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
             "dev": true,
             "dev": true,
+            "license": "BlueOak-1.0.0",
             "dependencies": {
             "dependencies": {
-                "universalify": "^2.0.0"
+                "lru-cache": "^10.2.0",
+                "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
             },
             },
-            "optionalDependencies": {
-                "graceful-fs": "^4.1.6"
+            "engines": {
+                "node": ">=16 || 14 >=14.18"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
             }
         },
             }
         },
-        "node_modules/jsx-ast-utils": {
-            "version": "3.3.5",
-            "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
-            "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+        "node_modules/path-scurry/node_modules/lru-cache": {
+            "version": "10.4.3",
+            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+            "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/path-to-regexp": {
+            "version": "0.1.12",
+            "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+            "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/path-type": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+            "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=8"
+            }
+        },
+        "node_modules/pathe": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+            "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
             "dev": true,
             "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/pathval": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz",
+            "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 14.16"
+            }
+        },
+        "node_modules/pbkdf2": {
+            "version": "3.1.3",
+            "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.3.tgz",
+            "integrity": "sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "array-includes": "^3.1.6",
-                "array.prototype.flat": "^1.3.1",
-                "object.assign": "^4.1.4",
-                "object.values": "^1.1.6"
+                "create-hash": "~1.1.3",
+                "create-hmac": "^1.1.7",
+                "ripemd160": "=2.0.1",
+                "safe-buffer": "^5.2.1",
+                "sha.js": "^2.4.11",
+                "to-buffer": "^1.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=4.0"
+                "node": ">=0.12"
             }
         },
             }
         },
-        "node_modules/junk": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
-            "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==",
+        "node_modules/pbkdf2/node_modules/create-hash": {
+            "version": "1.1.3",
+            "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+            "integrity": "sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=8"
+            "license": "MIT",
+            "dependencies": {
+                "cipher-base": "^1.0.1",
+                "inherits": "^2.0.1",
+                "ripemd160": "^2.0.0",
+                "sha.js": "^2.4.0"
             }
         },
             }
         },
-        "node_modules/keyv": {
-            "version": "4.5.3",
-            "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
-            "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==",
+        "node_modules/pbkdf2/node_modules/hash-base": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
+            "integrity": "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "json-buffer": "3.0.1"
+                "inherits": "^2.0.1"
             }
         },
             }
         },
-        "node_modules/kind-of": {
-            "version": "6.0.3",
-            "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
-            "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+        "node_modules/pbkdf2/node_modules/ripemd160": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
+            "integrity": "sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "hash-base": "^2.0.0",
+                "inherits": "^2.0.1"
+            }
+        },
+        "node_modules/picocolors": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+            "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/picomatch": {
+            "version": "2.3.1",
+            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+            "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=8.6"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/jonschlinkert"
+            }
+        },
+        "node_modules/pify": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+            "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "engines": {
                 "node": ">=0.10.0"
             }
         },
             "engines": {
                 "node": ">=0.10.0"
             }
         },
-        "node_modules/kleur": {
-            "version": "3.0.3",
-            "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
-            "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+        "node_modules/pirates": {
+            "version": "4.0.7",
+            "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
+            "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "engines": {
             "engines": {
-                "node": ">=6"
+                "node": ">= 6"
             }
         },
             }
         },
-        "node_modules/klona": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
-            "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
+        "node_modules/pkg-dir": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+            "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "find-up": "^4.0.0"
+            },
             "engines": {
             "engines": {
-                "node": ">= 8"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/laravel-echo": {
-            "version": "1.15.3",
-            "resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.15.3.tgz",
-            "integrity": "sha512-SRXzccaat6w4qKgZ4/rjFKr3nJfVxB+ly4V0MEJNIF1/TpERNXepo3uk7NnOjBGsiV/np1fl2XitAzW4Sa1s/w==",
+        "node_modules/pkg-dir/node_modules/find-up": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+            "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "locate-path": "^5.0.0",
+                "path-exists": "^4.0.0"
+            },
             "engines": {
             "engines": {
-                "node": ">=10"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/laravel-mix": {
-            "version": "6.0.49",
-            "resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.49.tgz",
-            "integrity": "sha512-bBMFpFjp26XfijPvY5y9zGKud7VqlyOE0OWUcPo3vTBY5asw8LTjafAbee1dhfLz6PWNqDziz69CP78ELSpfKw==",
+        "node_modules/pkg-dir/node_modules/locate-path": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+            "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/core": "^7.15.8",
-                "@babel/plugin-proposal-object-rest-spread": "^7.15.6",
-                "@babel/plugin-syntax-dynamic-import": "^7.8.3",
-                "@babel/plugin-transform-runtime": "^7.15.8",
-                "@babel/preset-env": "^7.15.8",
-                "@babel/runtime": "^7.15.4",
-                "@types/babel__core": "^7.1.16",
-                "@types/clean-css": "^4.2.5",
-                "@types/imagemin-gifsicle": "^7.0.1",
-                "@types/imagemin-mozjpeg": "^8.0.1",
-                "@types/imagemin-optipng": "^5.2.1",
-                "@types/imagemin-svgo": "^8.0.0",
-                "autoprefixer": "^10.4.0",
-                "babel-loader": "^8.2.3",
-                "chalk": "^4.1.2",
-                "chokidar": "^3.5.2",
-                "clean-css": "^5.2.4",
-                "cli-table3": "^0.6.0",
-                "collect.js": "^4.28.5",
-                "commander": "^7.2.0",
-                "concat": "^1.0.3",
-                "css-loader": "^5.2.6",
-                "cssnano": "^5.0.8",
-                "dotenv": "^10.0.0",
-                "dotenv-expand": "^5.1.0",
-                "file-loader": "^6.2.0",
-                "fs-extra": "^10.0.0",
-                "glob": "^7.2.0",
-                "html-loader": "^1.3.2",
-                "imagemin": "^7.0.1",
-                "img-loader": "^4.0.0",
-                "lodash": "^4.17.21",
-                "md5": "^2.3.0",
-                "mini-css-extract-plugin": "^1.6.2",
-                "node-libs-browser": "^2.2.1",
-                "postcss-load-config": "^3.1.0",
-                "postcss-loader": "^6.2.0",
-                "semver": "^7.3.5",
-                "strip-ansi": "^6.0.0",
-                "style-loader": "^2.0.0",
-                "terser": "^5.9.0",
-                "terser-webpack-plugin": "^5.2.4",
-                "vue-style-loader": "^4.1.3",
-                "webpack": "^5.60.0",
-                "webpack-cli": "^4.9.1",
-                "webpack-dev-server": "^4.7.3",
-                "webpack-merge": "^5.8.0",
-                "webpack-notifier": "^1.14.1",
-                "webpackbar": "^5.0.0-3",
-                "yargs": "^17.2.1"
-            },
-            "bin": {
-                "laravel-mix": "bin/cli.js",
-                "mix": "bin/cli.js"
-            },
-            "engines": {
-                "node": ">=12.14.0"
-            },
-            "peerDependencies": {
-                "@babel/core": "^7.15.8",
-                "@babel/plugin-proposal-object-rest-spread": "^7.15.6",
-                "@babel/plugin-syntax-dynamic-import": "^7.8.3",
-                "@babel/plugin-transform-runtime": "^7.15.8",
-                "@babel/preset-env": "^7.15.8",
-                "postcss": "^8.3.11",
-                "webpack": "^5.60.0",
-                "webpack-cli": "^4.9.1"
-            }
-        },
-        "node_modules/laravel-mix/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
+                "p-locate": "^4.1.0"
             },
             "engines": {
                 "node": ">=8"
             },
             "engines": {
                 "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
             }
         },
             }
         },
-        "node_modules/laravel-mix/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+        "node_modules/pkg-dir/node_modules/p-limit": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+            "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
+                "p-try": "^2.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": ">=6"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/laravel-mix/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "node_modules/pkg-dir/node_modules/p-locate": {
+            "version": "4.1.0",
+            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+            "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "color-name": "~1.1.4"
+                "p-limit": "^2.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=7.0.0"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/laravel-mix/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/laravel-mix/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "node_modules/possible-typed-array-names": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+            "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/laravel-mix/node_modules/lru-cache": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+        "node_modules/postcss": {
+            "version": "8.5.6",
+            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+            "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
             "dev": true,
             "dev": true,
+            "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"
+                }
+            ],
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "yallist": "^4.0.0"
+                "nanoid": "^3.3.11",
+                "picocolors": "^1.1.1",
+                "source-map-js": "^1.2.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": "^10 || ^12 || >=14"
             }
         },
             }
         },
-        "node_modules/laravel-mix/node_modules/semver": {
-            "version": "7.5.4",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-            "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+        "node_modules/postcss-calc": {
+            "version": "8.2.4",
+            "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz",
+            "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "lru-cache": "^6.0.0"
-            },
-            "bin": {
-                "semver": "bin/semver.js"
+                "postcss-selector-parser": "^6.0.9",
+                "postcss-value-parser": "^4.2.0"
             },
             },
-            "engines": {
-                "node": ">=10"
+            "peerDependencies": {
+                "postcss": "^8.2.2"
             }
         },
             }
         },
-        "node_modules/laravel-mix/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+        "node_modules/postcss-colormin": {
+            "version": "5.3.1",
+            "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz",
+            "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "has-flag": "^4.0.0"
+                "browserslist": "^4.21.4",
+                "caniuse-api": "^3.0.0",
+                "colord": "^2.9.1",
+                "postcss-value-parser": "^4.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/laravel-mix/node_modules/yallist": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-            "dev": true
-        },
-        "node_modules/launch-editor": {
-            "version": "2.6.0",
-            "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz",
-            "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==",
+        "node_modules/postcss-convert-values": {
+            "version": "5.1.3",
+            "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz",
+            "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "picocolors": "^1.0.0",
-                "shell-quote": "^1.7.3"
+                "browserslist": "^4.21.4",
+                "postcss-value-parser": "^4.2.0"
+            },
+            "engines": {
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/leven": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
-            "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+        "node_modules/postcss-discard-comments": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz",
+            "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=6"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/levn": {
-            "version": "0.4.1",
-            "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
-            "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+        "node_modules/postcss-discard-duplicates": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
+            "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "prelude-ls": "^1.2.1",
-                "type-check": "~0.4.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">= 0.8.0"
-            }
-        },
-        "node_modules/lie": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
-            "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
-            "dependencies": {
-                "immediate": "~3.0.5"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/lilconfig": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
-            "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+        "node_modules/postcss-discard-empty": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz",
+            "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=10"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/lines-and-columns": {
-            "version": "1.2.4",
-            "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
-            "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
-            "dev": true
-        },
-        "node_modules/loader-runner": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
-            "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+        "node_modules/postcss-discard-overridden": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
+            "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=6.11.5"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/loader-utils": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
-            "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+        "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==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "big.js": "^5.2.2",
-                "emojis-list": "^3.0.0",
-                "json5": "^2.1.2"
+                "postcss-value-parser": "^4.0.0",
+                "read-cache": "^1.0.0",
+                "resolve": "^1.1.7"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8.9.0"
+                "node": ">=14.0.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.0.0"
             }
         },
             }
         },
-        "node_modules/localforage": {
-            "version": "1.10.0",
-            "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
-            "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
+        "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==",
+            "dev": true,
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "lie": "3.1.1"
-            }
-        },
-        "node_modules/locate-path": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-            "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-            "dev": true,
-            "dependencies": {
-                "p-locate": "^5.0.0"
+                "camelcase-css": "^2.0.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": "^12 || ^14 || >= 16"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+                "type": "opencollective",
+                "url": "https://opencollective.com/postcss/"
+            },
+            "peerDependencies": {
+                "postcss": "^8.4.21"
             }
         },
             }
         },
-        "node_modules/lodash": {
-            "version": "4.17.21",
-            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-            "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
-        },
-        "node_modules/lodash-es": {
-            "version": "4.17.21",
-            "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
-            "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
-        },
-        "node_modules/lodash.debounce": {
-            "version": "4.0.8",
-            "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
-            "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
-            "dev": true
-        },
-        "node_modules/lodash.memoize": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
-            "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
-            "dev": true
-        },
-        "node_modules/lodash.merge": {
-            "version": "4.6.2",
-            "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-            "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-            "dev": true
-        },
-        "node_modules/lodash.uniq": {
-            "version": "4.5.0",
-            "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
-            "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
-            "dev": true
-        },
-        "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==",
+        "node_modules/postcss-load-config": {
+            "version": "3.1.4",
+            "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
+            "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "js-tokens": "^3.0.0 || ^4.0.0"
+                "lilconfig": "^2.0.5",
+                "yaml": "^1.10.2"
             },
             },
-            "bin": {
-                "loose-envify": "cli.js"
+            "engines": {
+                "node": ">= 10"
+            },
+            "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/lower-case": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
-            "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
+        "node_modules/postcss-load-config/node_modules/yaml": {
+            "version": "1.10.2",
+            "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+            "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "tslib": "^2.0.3"
+            "license": "ISC",
+            "engines": {
+                "node": ">= 6"
             }
         },
             }
         },
-        "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==",
+        "node_modules/postcss-loader": {
+            "version": "6.2.1",
+            "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz",
+            "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "yallist": "^3.0.2"
+                "cosmiconfig": "^7.0.0",
+                "klona": "^2.0.5",
+                "semver": "^7.3.5"
+            },
+            "engines": {
+                "node": ">= 12.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
+            },
+            "peerDependencies": {
+                "postcss": "^7.0.0 || ^8.0.1",
+                "webpack": "^5.0.0"
             }
         },
             }
         },
-        "node_modules/lz-string": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
-            "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+        "node_modules/postcss-loader/node_modules/semver": {
+            "version": "7.7.2",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+            "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "bin": {
             "bin": {
-                "lz-string": "bin/bin.js"
+                "semver": "bin/semver.js"
+            },
+            "engines": {
+                "node": ">=10"
             }
         },
             }
         },
-        "node_modules/make-dir": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-            "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+        "node_modules/postcss-merge-longhand": {
+            "version": "5.1.7",
+            "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz",
+            "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "semver": "^6.0.0"
+                "postcss-value-parser": "^4.2.0",
+                "stylehacks": "^5.1.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": "^10 || ^12 || >=14.0"
             },
             },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/makeerror": {
-            "version": "1.0.12",
-            "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
-            "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+        "node_modules/postcss-merge-rules": {
+            "version": "5.1.4",
+            "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz",
+            "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "tmpl": "1.0.5"
+                "browserslist": "^4.21.4",
+                "caniuse-api": "^3.0.0",
+                "cssnano-utils": "^3.1.0",
+                "postcss-selector-parser": "^6.0.5"
+            },
+            "engines": {
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/md5": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
-            "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
+        "node_modules/postcss-minify-font-values": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz",
+            "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "charenc": "0.0.2",
-                "crypt": "0.0.2",
-                "is-buffer": "~1.1.6"
+                "postcss-value-parser": "^4.2.0"
+            },
+            "engines": {
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/md5.js": {
-            "version": "1.3.5",
-            "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
-            "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+        "node_modules/postcss-minify-gradients": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz",
+            "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "hash-base": "^3.0.0",
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.1.2"
+                "colord": "^2.9.1",
+                "cssnano-utils": "^3.1.0",
+                "postcss-value-parser": "^4.2.0"
+            },
+            "engines": {
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/mdn-data": {
-            "version": "2.0.14",
-            "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
-            "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
-            "dev": true
-        },
-        "node_modules/media-typer": {
-            "version": "0.3.0",
-            "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
-            "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+        "node_modules/postcss-minify-params": {
+            "version": "5.1.4",
+            "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz",
+            "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "browserslist": "^4.21.4",
+                "cssnano-utils": "^3.1.0",
+                "postcss-value-parser": "^4.2.0"
+            },
             "engines": {
             "engines": {
-                "node": ">= 0.6"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/memfs": {
-            "version": "3.5.3",
-            "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz",
-            "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==",
+        "node_modules/postcss-minify-selectors": {
+            "version": "5.2.1",
+            "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz",
+            "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "fs-monkey": "^1.0.4"
+                "postcss-selector-parser": "^6.0.5"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 4.0.0"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/merge-descriptors": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-            "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
-            "dev": true
-        },
-        "node_modules/merge-stream": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
-            "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
-            "dev": true
-        },
-        "node_modules/merge2": {
-            "version": "1.4.1",
-            "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
-            "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+        "node_modules/postcss-modules-extract-imports": {
+            "version": "3.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz",
+            "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "engines": {
             "engines": {
-                "node": ">= 8"
+                "node": "^10 || ^12 || >= 14"
+            },
+            "peerDependencies": {
+                "postcss": "^8.1.0"
             }
         },
             }
         },
-        "node_modules/methods": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
-            "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
-            "dev": true,
+        "node_modules/postcss-modules-local-by-default": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz",
+            "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "icss-utils": "^5.0.0",
+                "postcss-selector-parser": "^7.0.0",
+                "postcss-value-parser": "^4.1.0"
+            },
             "engines": {
             "engines": {
-                "node": ">= 0.6"
+                "node": "^10 || ^12 || >= 14"
+            },
+            "peerDependencies": {
+                "postcss": "^8.1.0"
             }
         },
             }
         },
-        "node_modules/micromatch": {
-            "version": "4.0.5",
-            "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
-            "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+        "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": {
+            "version": "7.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+            "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "braces": "^3.0.2",
-                "picomatch": "^2.3.1"
+                "cssesc": "^3.0.0",
+                "util-deprecate": "^1.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8.6"
+                "node": ">=4"
             }
         },
             }
         },
-        "node_modules/miller-rabin": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
-            "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+        "node_modules/postcss-modules-scope": {
+            "version": "3.2.1",
+            "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz",
+            "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "bn.js": "^4.0.0",
-                "brorand": "^1.0.1"
+                "postcss-selector-parser": "^7.0.0"
             },
             },
-            "bin": {
-                "miller-rabin": "bin/miller-rabin"
+            "engines": {
+                "node": "^10 || ^12 || >= 14"
+            },
+            "peerDependencies": {
+                "postcss": "^8.1.0"
             }
         },
             }
         },
-        "node_modules/miller-rabin/node_modules/bn.js": {
-            "version": "4.12.0",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-            "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-            "dev": true
-        },
-        "node_modules/mime": {
-            "version": "1.6.0",
-            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+        "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": {
+            "version": "7.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+            "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
             "dev": true,
             "dev": true,
-            "bin": {
-                "mime": "cli.js"
+            "license": "MIT",
+            "dependencies": {
+                "cssesc": "^3.0.0",
+                "util-deprecate": "^1.0.2"
             },
             "engines": {
                 "node": ">=4"
             }
         },
             },
             "engines": {
                 "node": ">=4"
             }
         },
-        "node_modules/mime-db": {
-            "version": "1.52.0",
-            "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
-            "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+        "node_modules/postcss-modules-values": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
+            "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
+            "dependencies": {
+                "icss-utils": "^5.0.0"
+            },
             "engines": {
             "engines": {
-                "node": ">= 0.6"
+                "node": "^10 || ^12 || >= 14"
+            },
+            "peerDependencies": {
+                "postcss": "^8.1.0"
             }
         },
             }
         },
-        "node_modules/mime-types": {
-            "version": "2.1.35",
-            "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
-            "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+        "node_modules/postcss-nested": {
+            "version": "6.2.0",
+            "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+            "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
             "dev": true,
             "dev": true,
+            "funding": [
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/postcss/"
+                },
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/ai"
+                }
+            ],
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "mime-db": "1.52.0"
+                "postcss-selector-parser": "^6.1.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 0.6"
+                "node": ">=12.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.14"
             }
         },
             }
         },
-        "node_modules/mimic-fn": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
-            "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+        "node_modules/postcss-normalize-charset": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
+            "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=6"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/min-indent": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
-            "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+        "node_modules/postcss-normalize-display-values": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz",
+            "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "postcss-value-parser": "^4.2.0"
+            },
             "engines": {
             "engines": {
-                "node": ">=4"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/mini-css-extract-plugin": {
-            "version": "1.6.2",
-            "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz",
-            "integrity": "sha512-WhDvO3SjGm40oV5y26GjMJYjd2UMqrLAGKy5YS2/3QKJy2F7jgynuHTir/tgUUOiNQu5saXHdc8reo7YuhhT4Q==",
+        "node_modules/postcss-normalize-positions": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz",
+            "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "loader-utils": "^2.0.0",
-                "schema-utils": "^3.0.0",
-                "webpack-sources": "^1.1.0"
+                "postcss-value-parser": "^4.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 10.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
+                "node": "^10 || ^12 || >=14.0"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "webpack": "^4.4.0 || ^5.0.0"
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/mini-css-extract-plugin/node_modules/schema-utils": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-            "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+        "node_modules/postcss-normalize-repeat-style": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz",
+            "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@types/json-schema": "^7.0.8",
-                "ajv": "^6.12.5",
-                "ajv-keywords": "^3.5.2"
+                "postcss-value-parser": "^4.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 10.13.0"
+                "node": "^10 || ^12 || >=14.0"
             },
             },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/mini-svg-data-uri": {
-            "version": "1.4.4",
-            "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
-            "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
+        "node_modules/postcss-normalize-string": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz",
+            "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==",
             "dev": true,
             "dev": true,
-            "bin": {
-                "mini-svg-data-uri": "cli.js"
+            "license": "MIT",
+            "dependencies": {
+                "postcss-value-parser": "^4.2.0"
+            },
+            "engines": {
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/minimalistic-assert": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
-            "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
-            "dev": true
-        },
-        "node_modules/minimalistic-crypto-utils": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
-            "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==",
-            "dev": true
-        },
-        "node_modules/minimatch": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-            "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+        "node_modules/postcss-normalize-timing-functions": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz",
+            "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "brace-expansion": "^1.1.7"
+                "postcss-value-parser": "^4.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "*"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/minimist": {
-            "version": "1.2.8",
-            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
-            "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+        "node_modules/postcss-normalize-unicode": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz",
+            "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==",
             "dev": true,
             "dev": true,
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/moment": {
-            "version": "2.29.4",
-            "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
-            "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+            "license": "MIT",
+            "dependencies": {
+                "browserslist": "^4.21.4",
+                "postcss-value-parser": "^4.2.0"
+            },
             "engines": {
             "engines": {
-                "node": "*"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "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==",
-            "dev": true
-        },
-        "node_modules/multicast-dns": {
-            "version": "7.2.5",
-            "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",
-            "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==",
+        "node_modules/postcss-normalize-url": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz",
+            "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "dns-packet": "^5.2.2",
-                "thunky": "^1.0.2"
+                "normalize-url": "^6.0.1",
+                "postcss-value-parser": "^4.2.0"
             },
             },
-            "bin": {
-                "multicast-dns": "cli.js"
+            "engines": {
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/mz": {
-            "version": "2.7.0",
-            "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
-            "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+        "node_modules/postcss-normalize-whitespace": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz",
+            "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "any-promise": "^1.0.0",
-                "object-assign": "^4.0.1",
-                "thenify-all": "^1.0.0"
-            }
-        },
-        "node_modules/nanoid": {
-            "version": "3.3.6",
-            "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
-            "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
-            "dev": true,
-            "funding": [
-                {
-                    "type": "github",
-                    "url": "https://github.com/sponsors/ai"
-                }
-            ],
-            "bin": {
-                "nanoid": "bin/nanoid.cjs"
+                "postcss-value-parser": "^4.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/natural-compare": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-            "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
-            "dev": true
-        },
-        "node_modules/negotiator": {
-            "version": "0.6.3",
-            "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
-            "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+        "node_modules/postcss-ordered-values": {
+            "version": "5.1.3",
+            "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz",
+            "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "cssnano-utils": "^3.1.0",
+                "postcss-value-parser": "^4.2.0"
+            },
             "engines": {
             "engines": {
-                "node": ">= 0.6"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/neo-async": {
-            "version": "2.6.2",
-            "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
-            "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
-            "dev": true
-        },
-        "node_modules/no-case": {
-            "version": "3.0.4",
-            "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
-            "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
+        "node_modules/postcss-reduce-initial": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz",
+            "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "lower-case": "^2.0.2",
-                "tslib": "^2.0.3"
-            }
-        },
-        "node_modules/node-forge": {
-            "version": "1.3.1",
-            "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
-            "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
-            "dev": true,
+                "browserslist": "^4.21.4",
+                "caniuse-api": "^3.0.0"
+            },
             "engines": {
             "engines": {
-                "node": ">= 6.13.0"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/node-int64": {
-            "version": "0.4.0",
-            "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
-            "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
-            "dev": true
-        },
-        "node_modules/node-libs-browser": {
-            "version": "2.2.1",
-            "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
-            "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
+        "node_modules/postcss-reduce-transforms": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz",
+            "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "assert": "^1.1.1",
-                "browserify-zlib": "^0.2.0",
-                "buffer": "^4.3.0",
-                "console-browserify": "^1.1.0",
-                "constants-browserify": "^1.0.0",
-                "crypto-browserify": "^3.11.0",
-                "domain-browser": "^1.1.1",
-                "events": "^3.0.0",
-                "https-browserify": "^1.0.0",
-                "os-browserify": "^0.3.0",
-                "path-browserify": "0.0.1",
-                "process": "^0.11.10",
-                "punycode": "^1.2.4",
-                "querystring-es3": "^0.2.0",
-                "readable-stream": "^2.3.3",
-                "stream-browserify": "^2.0.1",
-                "stream-http": "^2.7.2",
-                "string_decoder": "^1.0.0",
-                "timers-browserify": "^2.0.4",
-                "tty-browserify": "0.0.0",
-                "url": "^0.11.0",
-                "util": "^0.11.0",
-                "vm-browserify": "^1.0.1"
+                "postcss-value-parser": "^4.2.0"
+            },
+            "engines": {
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/node-notifier": {
-            "version": "9.0.1",
-            "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-9.0.1.tgz",
-            "integrity": "sha512-fPNFIp2hF/Dq7qLDzSg4vZ0J4e9v60gJR+Qx7RbjbWqzPDdEqeVpEx5CFeDAELIl+A/woaaNn1fQ5nEVerMxJg==",
+        "node_modules/postcss-selector-parser": {
+            "version": "6.1.2",
+            "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+            "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "growly": "^1.3.0",
-                "is-wsl": "^2.2.0",
-                "semver": "^7.3.2",
-                "shellwords": "^0.1.1",
-                "uuid": "^8.3.0",
-                "which": "^2.0.2"
+                "cssesc": "^3.0.0",
+                "util-deprecate": "^1.0.2"
+            },
+            "engines": {
+                "node": ">=4"
             }
         },
             }
         },
-        "node_modules/node-notifier/node_modules/lru-cache": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+        "node_modules/postcss-svgo": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz",
+            "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "yallist": "^4.0.0"
+                "postcss-value-parser": "^4.2.0",
+                "svgo": "^2.7.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/node-notifier/node_modules/semver": {
-            "version": "7.5.4",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-            "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+        "node_modules/postcss-unique-selectors": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz",
+            "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "lru-cache": "^6.0.0"
-            },
-            "bin": {
-                "semver": "bin/semver.js"
+                "postcss-selector-parser": "^6.0.5"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": "^10 || ^12 || >=14.0"
+            },
+            "peerDependencies": {
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/node-notifier/node_modules/yallist": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-            "dev": true
-        },
-        "node_modules/node-releases": {
-            "version": "2.0.14",
-            "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
-            "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
-            "dev": true
+        "node_modules/postcss-value-parser": {
+            "version": "4.2.0",
+            "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+            "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/normalize-path": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-            "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+        "node_modules/prelude-ls": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+            "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=0.10.0"
+                "node": ">= 0.8.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==",
+        "node_modules/pretty-format": {
+            "version": "27.5.1",
+            "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
+            "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
+            "dependencies": {
+                "ansi-regex": "^5.0.1",
+                "ansi-styles": "^5.0.0",
+                "react-is": "^17.0.1"
+            },
             "engines": {
             "engines": {
-                "node": ">=0.10.0"
+                "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
             }
         },
             }
         },
-        "node_modules/normalize-url": {
-            "version": "6.1.0",
-            "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
-            "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
+        "node_modules/pretty-format/node_modules/ansi-styles": {
+            "version": "5.2.0",
+            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+            "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "engines": {
                 "node": ">=10"
             },
             "funding": {
             "engines": {
                 "node": ">=10"
             },
             "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
             }
         },
             }
         },
-        "node_modules/npm-run-path": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-            "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+        "node_modules/pretty-format/node_modules/react-is": {
+            "version": "17.0.2",
+            "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+            "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "path-key": "^3.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
+            "license": "MIT",
+            "peer": true
         },
         },
-        "node_modules/nth-check": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
-            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+        "node_modules/pretty-time": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz",
+            "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "boolbase": "^1.0.0"
-            },
-            "funding": {
-                "url": "https://github.com/fb55/nth-check?sponsor=1"
-            }
-        },
-        "node_modules/numeral": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz",
-            "integrity": "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "*"
+                "node": ">=4"
             }
         },
             }
         },
-        "node_modules/nwsapi": {
-            "version": "2.2.7",
-            "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
-            "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==",
-            "dev": true
-        },
-        "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==",
+        "node_modules/process": {
+            "version": "0.11.10",
+            "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+            "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=0.10.0"
+                "node": ">= 0.6.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==",
-            "dev": true,
-            "engines": {
-                "node": ">= 6"
-            }
+        "node_modules/process-nextick-args": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/object-inspect": {
-            "version": "1.12.3",
-            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
-            "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
+        "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==",
+            "license": "MIT",
+            "dependencies": {
+                "loose-envify": "^1.4.0",
+                "object-assign": "^4.1.1",
+                "react-is": "^16.13.1"
             }
         },
             }
         },
-        "node_modules/object-is": {
-            "version": "1.1.5",
-            "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
-            "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
-            "dev": true,
+        "node_modules/prop-types-extra": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
+            "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.3"
-            },
-            "engines": {
-                "node": ">= 0.4"
+                "react-is": "^16.3.2",
+                "warning": "^4.0.0"
             },
             },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
+            "peerDependencies": {
+                "react": ">=0.14.0"
             }
         },
             }
         },
-        "node_modules/object-keys": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-            "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.4"
-            }
+        "node_modules/property-expr": {
+            "version": "2.0.6",
+            "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
+            "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==",
+            "license": "MIT"
         },
         },
-        "node_modules/object.assign": {
-            "version": "4.1.4",
-            "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
-            "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
+        "node_modules/proxy-addr": {
+            "version": "2.0.7",
+            "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+            "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "has-symbols": "^1.0.3",
-                "object-keys": "^1.1.1"
+                "forwarded": "0.2.0",
+                "ipaddr.js": "1.9.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
+                "node": ">= 0.10"
             }
         },
             }
         },
-        "node_modules/object.entries": {
-            "version": "1.1.7",
-            "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz",
-            "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==",
+        "node_modules/proxy-addr/node_modules/ipaddr.js": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+            "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">= 0.4"
+                "node": ">= 0.10"
             }
         },
             }
         },
-        "node_modules/object.fromentries": {
-            "version": "2.0.7",
-            "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz",
-            "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==",
+        "node_modules/proxy-from-env": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+            "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/object.groupby": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz",
-            "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==",
+        "node_modules/public-encrypt": {
+            "version": "4.0.3",
+            "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
+            "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1"
+                "bn.js": "^4.1.0",
+                "browserify-rsa": "^4.0.0",
+                "create-hash": "^1.1.0",
+                "parse-asn1": "^5.0.0",
+                "randombytes": "^2.0.1",
+                "safe-buffer": "^5.1.2"
             }
         },
             }
         },
-        "node_modules/object.hasown": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz",
-            "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==",
+        "node_modules/public-encrypt/node_modules/bn.js": {
+            "version": "4.12.2",
+            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
+            "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/punycode": {
+            "version": "1.4.1",
+            "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+            "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/pusher-js": {
+            "version": "8.4.0",
+            "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.4.0.tgz",
+            "integrity": "sha512-wp3HqIIUc1GRyu1XrP6m2dgyE9MoCsXVsWNlohj0rjSkLf+a0jLvEyVubdg58oMk7bhjBWnFClgp8jfAa6Ak4Q==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
+                "tweetnacl": "^1.0.3"
             }
         },
             }
         },
-        "node_modules/object.values": {
-            "version": "1.1.7",
-            "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz",
-            "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==",
-            "dev": true,
+        "node_modules/qs": {
+            "version": "6.14.0",
+            "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+            "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+            "license": "BSD-3-Clause",
             "dependencies": {
             "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
+                "side-channel": "^1.1.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 0.4"
+                "node": ">=0.6"
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
             },
             "funding": {
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/obuf": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
-            "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
-            "dev": true
-        },
-        "node_modules/on-finished": {
-            "version": "2.4.1",
-            "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
-            "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+        "node_modules/querystring-es3": {
+            "version": "0.2.1",
+            "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+            "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "ee-first": "1.1.1"
-            },
             "engines": {
             "engines": {
-                "node": ">= 0.8"
+                "node": ">=0.4.x"
             }
         },
             }
         },
-        "node_modules/on-headers": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
-            "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+        "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==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">= 0.8"
-            }
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
+                },
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
+                }
+            ],
+            "license": "MIT"
         },
         },
-        "node_modules/once": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-            "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+        "node_modules/randombytes": {
+            "version": "2.1.0",
+            "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+            "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "wrappy": "1"
+                "safe-buffer": "^5.1.0"
             }
         },
             }
         },
-        "node_modules/onetime": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
-            "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+        "node_modules/randomfill": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+            "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "mimic-fn": "^2.1.0"
-            },
-            "engines": {
-                "node": ">=6"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+                "randombytes": "^2.0.5",
+                "safe-buffer": "^5.1.0"
             }
         },
             }
         },
-        "node_modules/open": {
-            "version": "8.4.2",
-            "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
-            "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+        "node_modules/range-parser": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+            "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "define-lazy-prop": "^2.0.0",
-                "is-docker": "^2.1.1",
-                "is-wsl": "^2.2.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=12"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
-        "node_modules/openseadragon": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/openseadragon/-/openseadragon-4.1.0.tgz",
-            "integrity": "sha512-XMMzf5apmshvIvxvqMwiW9dJ07dol4zudvV1oFnoZuIpSZP3c3tlFjGbyOKHGhb1k4jmHQ7b7koG9vCHdKvC/A==",
-            "funding": {
-                "url": "https://opencollective.com/openseadragon"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/optionator": {
-            "version": "0.9.3",
-            "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
-            "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+        "node_modules/raw-body": {
+            "version": "2.5.2",
+            "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
+            "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@aashutoshrathi/word-wrap": "^1.2.3",
-                "deep-is": "^0.1.3",
-                "fast-levenshtein": "^2.0.6",
-                "levn": "^0.4.1",
-                "prelude-ls": "^1.2.1",
-                "type-check": "^0.4.0"
+                "bytes": "3.1.2",
+                "http-errors": "2.0.0",
+                "iconv-lite": "0.4.24",
+                "unpipe": "1.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 0.8.0"
+                "node": ">= 0.8"
             }
         },
             }
         },
-        "node_modules/os-browserify": {
-            "version": "0.3.0",
-            "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
-            "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==",
-            "dev": true
-        },
-        "node_modules/p-limit": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-            "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-            "dev": true,
-            "dependencies": {
-                "yocto-queue": "^0.1.0"
-            },
+        "node_modules/react": {
+            "version": "19.1.0",
+            "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
+            "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "node_modules/p-locate": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-            "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-            "dev": true,
+        "node_modules/react-bootstrap": {
+            "version": "2.10.10",
+            "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.10.tgz",
+            "integrity": "sha512-gMckKUqn8aK/vCnfwoBpBVFUGT9SVQxwsYrp9yDHt0arXMamxALerliKBxr1TPbntirK/HGrUAHYbAeQTa9GHQ==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "p-limit": "^3.0.2"
+                "@babel/runtime": "^7.24.7",
+                "@restart/hooks": "^0.4.9",
+                "@restart/ui": "^1.9.4",
+                "@types/prop-types": "^15.7.12",
+                "@types/react-transition-group": "^4.4.6",
+                "classnames": "^2.3.2",
+                "dom-helpers": "^5.2.1",
+                "invariant": "^2.2.4",
+                "prop-types": "^15.8.1",
+                "prop-types-extra": "^1.1.0",
+                "react-transition-group": "^4.4.5",
+                "uncontrollable": "^7.2.1",
+                "warning": "^4.0.3"
             },
             },
-            "engines": {
-                "node": ">=10"
+            "peerDependencies": {
+                "@types/react": ">=16.14.8",
+                "react": ">=16.14.0",
+                "react-dom": ">=16.14.0"
             },
             },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+            "peerDependenciesMeta": {
+                "@types/react": {
+                    "optional": true
+                }
             }
         },
             }
         },
-        "node_modules/p-pipe": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz",
-            "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
+        "node_modules/react-dom": {
+            "version": "19.1.0",
+            "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
+            "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
+            "license": "MIT",
+            "dependencies": {
+                "scheduler": "^0.26.0"
             },
             },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+            "peerDependencies": {
+                "react": "^19.1.0"
             }
         },
             }
         },
-        "node_modules/p-retry": {
-            "version": "4.6.2",
-            "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
-            "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
-            "dev": true,
+        "node_modules/react-fast-compare": {
+            "version": "2.0.4",
+            "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
+            "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==",
+            "license": "MIT"
+        },
+        "node_modules/react-helmet": {
+            "version": "6.1.0",
+            "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz",
+            "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@types/retry": "0.12.0",
-                "retry": "^0.13.1"
+                "object-assign": "^4.1.1",
+                "prop-types": "^15.7.2",
+                "react-fast-compare": "^3.1.1",
+                "react-side-effect": "^2.1.0"
             },
             },
-            "engines": {
-                "node": ">=8"
+            "peerDependencies": {
+                "react": ">=16.3.0"
             }
         },
             }
         },
-        "node_modules/p-try": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-            "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
+        "node_modules/react-helmet/node_modules/react-fast-compare": {
+            "version": "3.2.2",
+            "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
+            "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
+            "license": "MIT"
+        },
+        "node_modules/react-helmet/node_modules/react-side-effect": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz",
+            "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==",
+            "license": "MIT",
+            "peerDependencies": {
+                "react": "^16.3.0 || ^17.0.0 || ^18.0.0"
             }
         },
             }
         },
-        "node_modules/pako": {
-            "version": "1.0.11",
-            "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
-            "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
-            "dev": true
+        "node_modules/react-i18next": {
+            "version": "15.5.3",
+            "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.5.3.tgz",
+            "integrity": "sha512-ypYmOKOnjqPEJZO4m1BI0kS8kWqkBNsKYyhVUfij0gvjy9xJNoG/VcGkxq5dRlVwzmrmY1BQMAmpbbUBLwC4Kw==",
+            "license": "MIT",
+            "dependencies": {
+                "@babel/runtime": "^7.27.6",
+                "html-parse-stringify": "^3.0.1"
+            },
+            "peerDependencies": {
+                "i18next": ">= 23.2.3",
+                "react": ">= 16.8.0",
+                "typescript": "^5"
+            },
+            "peerDependenciesMeta": {
+                "react-dom": {
+                    "optional": true
+                },
+                "react-native": {
+                    "optional": true
+                },
+                "typescript": {
+                    "optional": true
+                }
+            }
         },
         },
-        "node_modules/param-case": {
+        "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==",
+            "license": "MIT"
+        },
+        "node_modules/react-lifecycles-compat": {
             "version": "3.0.4",
             "version": "3.0.4",
-            "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
-            "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
+            "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+            "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
+            "license": "MIT"
+        },
+        "node_modules/react-refresh": {
+            "version": "0.17.0",
+            "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
+            "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "dot-case": "^3.0.4",
-                "tslib": "^2.0.3"
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "node_modules/parent-module": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-            "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-            "dev": true,
+        "node_modules/react-router": {
+            "version": "6.30.1",
+            "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz",
+            "integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "callsites": "^3.0.0"
+                "@remix-run/router": "1.23.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=6"
+                "node": ">=14.0.0"
+            },
+            "peerDependencies": {
+                "react": ">=16.8"
             }
         },
             }
         },
-        "node_modules/parse-asn1": {
-            "version": "5.1.6",
-            "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
-            "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
-            "dev": true,
+        "node_modules/react-router-bootstrap": {
+            "version": "0.26.3",
+            "resolved": "https://registry.npmjs.org/react-router-bootstrap/-/react-router-bootstrap-0.26.3.tgz",
+            "integrity": "sha512-cBgcWekti6lFRl/vXP8ZfKuA/0Qe7L5xBjQ6OwbGI30+NSAAH/YZGbO6whSeBWFILn6uTVOX939HDGhs+5WzOw==",
+            "license": "Apache-2.0",
             "dependencies": {
             "dependencies": {
-                "asn1.js": "^5.2.0",
-                "browserify-aes": "^1.0.0",
-                "evp_bytestokey": "^1.0.0",
-                "pbkdf2": "^3.0.3",
-                "safe-buffer": "^5.1.1"
+                "prop-types": "^15.7.2"
+            },
+            "peerDependencies": {
+                "react": ">=16.13.1",
+                "react-router-dom": ">=6.0.0"
             }
         },
             }
         },
-        "node_modules/parse-json": {
-            "version": "5.2.0",
-            "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
-            "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
-            "dev": true,
+        "node_modules/react-router-dom": {
+            "version": "6.30.1",
+            "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz",
+            "integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/code-frame": "^7.0.0",
-                "error-ex": "^1.3.1",
-                "json-parse-even-better-errors": "^2.3.0",
-                "lines-and-columns": "^1.1.6"
+                "@remix-run/router": "1.23.0",
+                "react-router": "6.30.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=14.0.0"
             },
             },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
+            "peerDependencies": {
+                "react": ">=16.8",
+                "react-dom": ">=16.8"
             }
         },
             }
         },
-        "node_modules/parse5": {
-            "version": "7.1.2",
-            "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
-            "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
-            "dev": true,
+        "node_modules/react-smooth": {
+            "version": "4.0.4",
+            "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz",
+            "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "entities": "^4.4.0"
+                "fast-equals": "^5.0.1",
+                "prop-types": "^15.8.1",
+                "react-transition-group": "^4.4.5"
             },
             },
-            "funding": {
-                "url": "https://github.com/inikulin/parse5?sponsor=1"
+            "peerDependencies": {
+                "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+                "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
             }
         },
             }
         },
-        "node_modules/parse5/node_modules/entities": {
-            "version": "4.5.0",
-            "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
-            "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.12"
+        "node_modules/react-transition-group": {
+            "version": "4.4.5",
+            "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+            "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+            "license": "BSD-3-Clause",
+            "dependencies": {
+                "@babel/runtime": "^7.5.5",
+                "dom-helpers": "^5.0.1",
+                "loose-envify": "^1.4.0",
+                "prop-types": "^15.6.2"
             },
             },
-            "funding": {
-                "url": "https://github.com/fb55/entities?sponsor=1"
+            "peerDependencies": {
+                "react": ">=16.6.0",
+                "react-dom": ">=16.6.0"
             }
         },
             }
         },
-        "node_modules/parseurl": {
-            "version": "1.3.3",
-            "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
-            "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+        "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==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">= 0.8"
+            "license": "MIT",
+            "peer": true,
+            "dependencies": {
+                "pify": "^2.3.0"
             }
         },
             }
         },
-        "node_modules/pascal-case": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
-            "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
+        "node_modules/readable-stream": {
+            "version": "2.3.8",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+            "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "no-case": "^3.0.4",
-                "tslib": "^2.0.3"
+                "core-util-is": "~1.0.0",
+                "inherits": "~2.0.3",
+                "isarray": "~1.0.0",
+                "process-nextick-args": "~2.0.0",
+                "safe-buffer": "~5.1.1",
+                "string_decoder": "~1.1.1",
+                "util-deprecate": "~1.0.1"
             }
         },
             }
         },
-        "node_modules/path-browserify": {
-            "version": "0.0.1",
-            "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
-            "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
-            "dev": true
+        "node_modules/readable-stream/node_modules/safe-buffer": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/path-exists": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-            "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+        "node_modules/readable-stream/node_modules/string_decoder": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=8"
+            "license": "MIT",
+            "dependencies": {
+                "safe-buffer": "~5.1.0"
             }
         },
             }
         },
-        "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==",
+        "node_modules/readdirp": {
+            "version": "3.6.0",
+            "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+            "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "picomatch": "^2.2.1"
+            },
             "engines": {
             "engines": {
-                "node": ">=0.10.0"
+                "node": ">=8.10.0"
             }
         },
             }
         },
-        "node_modules/path-key": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-            "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-            "dev": true,
+        "node_modules/recharts": {
+            "version": "2.15.4",
+            "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz",
+            "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==",
+            "license": "MIT",
+            "dependencies": {
+                "clsx": "^2.0.0",
+                "eventemitter3": "^4.0.1",
+                "lodash": "^4.17.21",
+                "react-is": "^18.3.1",
+                "react-smooth": "^4.0.4",
+                "recharts-scale": "^0.4.4",
+                "tiny-invariant": "^1.3.1",
+                "victory-vendor": "^36.6.8"
+            },
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">=14"
+            },
+            "peerDependencies": {
+                "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+                "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.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==",
-            "dev": true
-        },
-        "node_modules/path-to-regexp": {
-            "version": "0.1.7",
-            "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-            "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
-            "dev": true
-        },
-        "node_modules/path-type": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-            "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+        "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==",
+            "license": "MIT",
+            "dependencies": {
+                "decimal.js-light": "^2.4.1"
+            }
+        },
+        "node_modules/recharts/node_modules/react-is": {
+            "version": "18.3.1",
+            "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+            "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+            "license": "MIT"
+        },
+        "node_modules/rechoir": {
+            "version": "0.7.1",
+            "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
+            "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "resolve": "^1.9.0"
+            },
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.10"
             }
         },
             }
         },
-        "node_modules/pbkdf2": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
-            "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
+        "node_modules/redent": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+            "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "create-hash": "^1.1.2",
-                "create-hmac": "^1.1.4",
-                "ripemd160": "^2.0.1",
-                "safe-buffer": "^5.0.1",
-                "sha.js": "^2.4.8"
+                "indent-string": "^4.0.0",
+                "strip-indent": "^3.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=0.12"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/picocolors": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-            "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
-            "dev": true
-        },
-        "node_modules/picomatch": {
-            "version": "2.3.1",
-            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-            "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+        "node_modules/reflect.getprototypeof": {
+            "version": "1.0.10",
+            "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
+            "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "call-bind": "^1.0.8",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.9",
+                "es-errors": "^1.3.0",
+                "es-object-atoms": "^1.0.0",
+                "get-intrinsic": "^1.2.7",
+                "get-proto": "^1.0.1",
+                "which-builtin-type": "^1.2.1"
+            },
             "engines": {
             "engines": {
-                "node": ">=8.6"
+                "node": ">= 0.4"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/sponsors/jonschlinkert"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/pify": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-            "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+        "node_modules/regenerate": {
+            "version": "1.4.2",
+            "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+            "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=0.10.0"
-            }
+            "license": "MIT"
         },
         },
-        "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==",
+        "node_modules/regenerate-unicode-properties": {
+            "version": "10.2.0",
+            "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz",
+            "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "regenerate": "^1.4.2"
+            },
             "engines": {
             "engines": {
-                "node": ">= 6"
+                "node": ">=4"
             }
         },
             }
         },
-        "node_modules/pkg-dir": {
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-            "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+        "node_modules/regex-parser": {
+            "version": "2.3.1",
+            "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.3.1.tgz",
+            "integrity": "sha512-yXLRqatcCuKtVHsWrNg0JL3l1zGfdXeEvDa0bdu4tCDQw0RpMDZsqbkyRTUnKMR0tXF627V2oEWjBEaEdqTwtQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/regexp.prototype.flags": {
+            "version": "1.5.4",
+            "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
+            "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "find-up": "^4.0.0"
+                "call-bind": "^1.0.8",
+                "define-properties": "^1.2.1",
+                "es-errors": "^1.3.0",
+                "get-proto": "^1.0.1",
+                "gopd": "^1.2.0",
+                "set-function-name": "^2.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/pkg-dir/node_modules/find-up": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-            "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+        "node_modules/regexpu-core": {
+            "version": "6.2.0",
+            "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz",
+            "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "locate-path": "^5.0.0",
-                "path-exists": "^4.0.0"
+                "regenerate": "^1.4.2",
+                "regenerate-unicode-properties": "^10.2.0",
+                "regjsgen": "^0.8.0",
+                "regjsparser": "^0.12.0",
+                "unicode-match-property-ecmascript": "^2.0.0",
+                "unicode-match-property-value-ecmascript": "^2.1.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
+                "node": ">=4"
             }
         },
             }
         },
-        "node_modules/pkg-dir/node_modules/locate-path": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-            "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+        "node_modules/regjsgen": {
+            "version": "0.8.0",
+            "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz",
+            "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/regjsparser": {
+            "version": "0.12.0",
+            "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz",
+            "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==",
             "dev": true,
             "dev": true,
+            "license": "BSD-2-Clause",
             "dependencies": {
             "dependencies": {
-                "p-locate": "^4.1.0"
+                "jsesc": "~3.0.2"
             },
             },
-            "engines": {
-                "node": ">=8"
+            "bin": {
+                "regjsparser": "bin/parser"
             }
         },
             }
         },
-        "node_modules/pkg-dir/node_modules/p-limit": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-            "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+        "node_modules/regjsparser/node_modules/jsesc": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
+            "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "p-try": "^2.0.0"
+            "license": "MIT",
+            "bin": {
+                "jsesc": "bin/jsesc"
             },
             "engines": {
                 "node": ">=6"
             },
             "engines": {
                 "node": ">=6"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/pkg-dir/node_modules/p-locate": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-            "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+        "node_modules/relateurl": {
+            "version": "0.2.7",
+            "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+            "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "p-limit": "^2.2.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=8"
+                "node": ">= 0.10"
             }
         },
             }
         },
-        "node_modules/possible-typed-array-names": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
-            "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+        "node_modules/replace-ext": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
+            "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">= 0.4"
+                "node": ">= 0.10"
             }
         },
             }
         },
-        "node_modules/postcss": {
-            "version": "8.4.29",
-            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
-            "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==",
+        "node_modules/require-directory": {
+            "version": "2.1.1",
+            "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+            "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
             "dev": true,
             "dev": true,
-            "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"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >=14"
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "node_modules/postcss-calc": {
-            "version": "8.2.4",
-            "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz",
-            "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==",
+        "node_modules/require-from-string": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+            "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "postcss-selector-parser": "^6.0.9",
-                "postcss-value-parser": "^4.2.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.2"
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "node_modules/postcss-colormin": {
-            "version": "5.3.1",
-            "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz",
-            "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==",
+        "node_modules/requires-port": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+            "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/resolve": {
+            "version": "1.22.10",
+            "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+            "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserslist": "^4.21.4",
-                "caniuse-api": "^3.0.0",
-                "colord": "^2.9.1",
-                "postcss-value-parser": "^4.2.0"
+                "is-core-module": "^2.16.0",
+                "path-parse": "^1.0.7",
+                "supports-preserve-symlinks-flag": "^1.0.0"
+            },
+            "bin": {
+                "resolve": "bin/resolve"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
+                "node": ">= 0.4"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/postcss-convert-values": {
-            "version": "5.1.3",
-            "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz",
-            "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==",
+        "node_modules/resolve-cwd": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+            "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserslist": "^4.21.4",
-                "postcss-value-parser": "^4.2.0"
+                "resolve-from": "^5.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/postcss-discard-comments": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz",
-            "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==",
+        "node_modules/resolve-cwd/node_modules/resolve-from": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+            "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/postcss-discard-duplicates": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
-            "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
+        "node_modules/resolve-from": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+            "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">=4"
             }
         },
             }
         },
-        "node_modules/postcss-discard-empty": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz",
-            "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==",
+        "node_modules/resolve-url-loader": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz",
+            "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": "^10 || ^12 || >=14.0"
+            "license": "MIT",
+            "dependencies": {
+                "adjust-sourcemap-loader": "^4.0.0",
+                "convert-source-map": "^1.7.0",
+                "loader-utils": "^2.0.0",
+                "postcss": "^8.2.14",
+                "source-map": "0.6.1"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "engines": {
+                "node": ">=12"
             }
         },
             }
         },
-        "node_modules/postcss-discard-overridden": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
-            "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
+        "node_modules/resolve-url-loader/node_modules/convert-source-map": {
+            "version": "1.9.0",
+            "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+            "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/retry": {
+            "version": "0.13.1",
+            "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+            "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">= 4"
             }
         },
             }
         },
-        "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==",
+        "node_modules/reusify": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+            "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "postcss-value-parser": "^4.0.0",
-                "read-cache": "^1.0.0",
-                "resolve": "^1.1.7"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=14.0.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.0.0"
+                "iojs": ">=1.0.0",
+                "node": ">=0.10.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==",
+        "node_modules/rimraf": {
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+            "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+            "deprecated": "Rimraf versions prior to v4 are no longer supported",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "camelcase-css": "^2.0.1"
+                "glob": "^7.1.3"
             },
             },
-            "engines": {
-                "node": "^12 || ^14 || >= 16"
+            "bin": {
+                "rimraf": "bin.js"
             },
             "funding": {
             },
             "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/postcss/"
-            },
-            "peerDependencies": {
-                "postcss": "^8.4.21"
+                "url": "https://github.com/sponsors/isaacs"
             }
         },
             }
         },
-        "node_modules/postcss-load-config": {
-            "version": "3.1.4",
-            "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
-            "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
+        "node_modules/ripemd160": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+            "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "lilconfig": "^2.0.5",
-                "yaml": "^1.10.2"
-            },
-            "engines": {
-                "node": ">= 10"
+                "hash-base": "^3.0.0",
+                "inherits": "^2.0.1"
+            }
+        },
+        "node_modules/rollup": {
+            "version": "4.44.0",
+            "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz",
+            "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/estree": "1.0.8"
             },
             },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/postcss/"
+            "bin": {
+                "rollup": "dist/bin/rollup"
             },
             },
-            "peerDependencies": {
-                "postcss": ">=8.0.9",
-                "ts-node": ">=9.0.0"
+            "engines": {
+                "node": ">=18.0.0",
+                "npm": ">=8.0.0"
             },
             },
-            "peerDependenciesMeta": {
-                "postcss": {
-                    "optional": true
+            "optionalDependencies": {
+                "@rollup/rollup-android-arm-eabi": "4.44.0",
+                "@rollup/rollup-android-arm64": "4.44.0",
+                "@rollup/rollup-darwin-arm64": "4.44.0",
+                "@rollup/rollup-darwin-x64": "4.44.0",
+                "@rollup/rollup-freebsd-arm64": "4.44.0",
+                "@rollup/rollup-freebsd-x64": "4.44.0",
+                "@rollup/rollup-linux-arm-gnueabihf": "4.44.0",
+                "@rollup/rollup-linux-arm-musleabihf": "4.44.0",
+                "@rollup/rollup-linux-arm64-gnu": "4.44.0",
+                "@rollup/rollup-linux-arm64-musl": "4.44.0",
+                "@rollup/rollup-linux-loongarch64-gnu": "4.44.0",
+                "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0",
+                "@rollup/rollup-linux-riscv64-gnu": "4.44.0",
+                "@rollup/rollup-linux-riscv64-musl": "4.44.0",
+                "@rollup/rollup-linux-s390x-gnu": "4.44.0",
+                "@rollup/rollup-linux-x64-gnu": "4.44.0",
+                "@rollup/rollup-linux-x64-musl": "4.44.0",
+                "@rollup/rollup-win32-arm64-msvc": "4.44.0",
+                "@rollup/rollup-win32-ia32-msvc": "4.44.0",
+                "@rollup/rollup-win32-x64-msvc": "4.44.0",
+                "fsevents": "~2.3.2"
+            }
+        },
+        "node_modules/rrweb-cssom": {
+            "version": "0.8.0",
+            "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
+            "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "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==",
+            "dev": true,
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
                 },
                 },
-                "ts-node": {
-                    "optional": true
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
                 }
                 }
+            ],
+            "license": "MIT",
+            "dependencies": {
+                "queue-microtask": "^1.2.2"
             }
         },
             }
         },
-        "node_modules/postcss-loader": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz",
-            "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==",
+        "node_modules/safe-array-concat": {
+            "version": "1.1.3",
+            "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz",
+            "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "cosmiconfig": "^7.0.0",
-                "klona": "^2.0.5",
-                "semver": "^7.3.5"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.2",
+                "get-intrinsic": "^1.2.6",
+                "has-symbols": "^1.1.0",
+                "isarray": "^2.0.5"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 12.13.0"
+                "node": ">=0.4"
             },
             "funding": {
             },
             "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            },
-            "peerDependencies": {
-                "postcss": "^7.0.0 || ^8.0.1",
-                "webpack": "^5.0.0"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/postcss-loader/node_modules/lru-cache": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-            "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+        "node_modules/safe-array-concat/node_modules/isarray": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+            "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/safe-buffer": {
+            "version": "5.2.1",
+            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+            "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+            "dev": true,
+            "funding": [
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/feross"
+                },
+                {
+                    "type": "patreon",
+                    "url": "https://www.patreon.com/feross"
+                },
+                {
+                    "type": "consulting",
+                    "url": "https://feross.org/support"
+                }
+            ],
+            "license": "MIT"
+        },
+        "node_modules/safe-push-apply": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz",
+            "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "yallist": "^4.0.0"
+                "es-errors": "^1.3.0",
+                "isarray": "^2.0.5"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/postcss-loader/node_modules/semver": {
-            "version": "7.5.4",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-            "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+        "node_modules/safe-push-apply/node_modules/isarray": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+            "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/safe-regex-test": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz",
+            "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "lru-cache": "^6.0.0"
-            },
-            "bin": {
-                "semver": "bin/semver.js"
+                "call-bound": "^1.0.2",
+                "es-errors": "^1.3.0",
+                "is-regex": "^1.2.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=10"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/postcss-loader/node_modules/yallist": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-            "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-            "dev": true
+        "node_modules/safer-buffer": {
+            "version": "2.1.2",
+            "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/postcss-merge-longhand": {
-            "version": "5.1.7",
-            "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz",
-            "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==",
+        "node_modules/sass": {
+            "version": "1.89.2",
+            "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz",
+            "integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-value-parser": "^4.2.0",
-                "stylehacks": "^5.1.1"
+                "chokidar": "^4.0.0",
+                "immutable": "^5.0.2",
+                "source-map-js": ">=0.6.2 <2.0.0"
+            },
+            "bin": {
+                "sass": "sass.js"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
+                "node": ">=14.0.0"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "optionalDependencies": {
+                "@parcel/watcher": "^2.4.1"
             }
         },
             }
         },
-        "node_modules/postcss-merge-rules": {
-            "version": "5.1.4",
-            "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz",
-            "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==",
+        "node_modules/sass/node_modules/chokidar": {
+            "version": "4.0.3",
+            "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+            "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserslist": "^4.21.4",
-                "caniuse-api": "^3.0.0",
-                "cssnano-utils": "^3.1.0",
-                "postcss-selector-parser": "^6.0.5"
+                "readdirp": "^4.0.1"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
+                "node": ">= 14.16.0"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "funding": {
+                "url": "https://paulmillr.com/funding/"
             }
         },
             }
         },
-        "node_modules/postcss-minify-font-values": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz",
-            "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==",
+        "node_modules/sass/node_modules/readdirp": {
+            "version": "4.1.2",
+            "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+            "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "postcss-value-parser": "^4.2.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
+                "node": ">= 14.18.0"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "funding": {
+                "type": "individual",
+                "url": "https://paulmillr.com/funding/"
             }
         },
             }
         },
-        "node_modules/postcss-minify-gradients": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz",
-            "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==",
+        "node_modules/saxes": {
+            "version": "6.0.0",
+            "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+            "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "colord": "^2.9.1",
-                "cssnano-utils": "^3.1.0",
-                "postcss-value-parser": "^4.2.0"
+                "xmlchars": "^2.2.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">=v12.22.7"
             }
         },
             }
         },
-        "node_modules/postcss-minify-params": {
-            "version": "5.1.4",
-            "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz",
-            "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==",
+        "node_modules/scheduler": {
+            "version": "0.26.0",
+            "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
+            "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
+            "license": "MIT"
+        },
+        "node_modules/schema-utils": {
+            "version": "2.7.1",
+            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
+            "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserslist": "^4.21.4",
-                "cssnano-utils": "^3.1.0",
-                "postcss-value-parser": "^4.2.0"
+                "@types/json-schema": "^7.0.5",
+                "ajv": "^6.12.4",
+                "ajv-keywords": "^3.5.2"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
+                "node": ">= 8.9.0"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
             }
         },
             }
         },
-        "node_modules/postcss-minify-selectors": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz",
-            "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==",
+        "node_modules/select-hose": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
+            "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/selfsigned": {
+            "version": "2.4.1",
+            "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz",
+            "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-selector-parser": "^6.0.5"
+                "@types/node-forge": "^1.3.0",
+                "node-forge": "^1"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">=10"
             }
         },
             }
         },
-        "node_modules/postcss-modules-extract-imports": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
-            "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
+        "node_modules/semver": {
+            "version": "6.3.1",
+            "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+            "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": "^10 || ^12 || >= 14"
-            },
-            "peerDependencies": {
-                "postcss": "^8.1.0"
+            "license": "ISC",
+            "bin": {
+                "semver": "bin/semver.js"
             }
         },
             }
         },
-        "node_modules/postcss-modules-local-by-default": {
-            "version": "4.0.3",
-            "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz",
-            "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==",
+        "node_modules/send": {
+            "version": "0.19.0",
+            "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
+            "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "icss-utils": "^5.0.0",
-                "postcss-selector-parser": "^6.0.2",
-                "postcss-value-parser": "^4.1.0"
+                "debug": "2.6.9",
+                "depd": "2.0.0",
+                "destroy": "1.2.0",
+                "encodeurl": "~1.0.2",
+                "escape-html": "~1.0.3",
+                "etag": "~1.8.1",
+                "fresh": "0.5.2",
+                "http-errors": "2.0.0",
+                "mime": "1.6.0",
+                "ms": "2.1.3",
+                "on-finished": "2.4.1",
+                "range-parser": "~1.2.1",
+                "statuses": "2.0.1"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >= 14"
-            },
-            "peerDependencies": {
-                "postcss": "^8.1.0"
+                "node": ">= 0.8.0"
             }
         },
             }
         },
-        "node_modules/postcss-modules-scope": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
-            "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
+        "node_modules/send/node_modules/debug": {
+            "version": "2.6.9",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+            "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-selector-parser": "^6.0.4"
-            },
+                "ms": "2.0.0"
+            }
+        },
+        "node_modules/send/node_modules/debug/node_modules/ms": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+            "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/send/node_modules/encodeurl": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+            "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >= 14"
-            },
-            "peerDependencies": {
-                "postcss": "^8.1.0"
+                "node": ">= 0.8"
             }
         },
             }
         },
-        "node_modules/postcss-modules-values": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
-            "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
+        "node_modules/serialize-javascript": {
+            "version": "6.0.2",
+            "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+            "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
             "dev": true,
             "dev": true,
+            "license": "BSD-3-Clause",
             "dependencies": {
             "dependencies": {
-                "icss-utils": "^5.0.0"
-            },
-            "engines": {
-                "node": "^10 || ^12 || >= 14"
-            },
-            "peerDependencies": {
-                "postcss": "^8.1.0"
+                "randombytes": "^2.1.0"
             }
         },
             }
         },
-        "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==",
+        "node_modules/serve-index": {
+            "version": "1.9.1",
+            "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+            "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-selector-parser": "^6.0.11"
+                "accepts": "~1.3.4",
+                "batch": "0.6.1",
+                "debug": "2.6.9",
+                "escape-html": "~1.0.3",
+                "http-errors": "~1.6.2",
+                "mime-types": "~2.1.17",
+                "parseurl": "~1.3.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=12.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/postcss/"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.14"
+                "node": ">= 0.8.0"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-charset": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
-            "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
+        "node_modules/serve-index/node_modules/debug": {
+            "version": "2.6.9",
+            "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+            "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "license": "MIT",
+            "dependencies": {
+                "ms": "2.0.0"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-display-values": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz",
-            "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==",
+        "node_modules/serve-index/node_modules/depd": {
+            "version": "1.1.2",
+            "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+            "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "postcss-value-parser": "^4.2.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-positions": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz",
-            "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==",
+        "node_modules/serve-index/node_modules/http-errors": {
+            "version": "1.6.3",
+            "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+            "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-value-parser": "^4.2.0"
+                "depd": "~1.1.2",
+                "inherits": "2.0.3",
+                "setprototypeof": "1.1.0",
+                "statuses": ">= 1.4.0 < 2"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-repeat-style": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz",
-            "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==",
+        "node_modules/serve-index/node_modules/inherits": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+            "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "postcss-value-parser": "^4.2.0"
-            },
+            "license": "ISC"
+        },
+        "node_modules/serve-index/node_modules/ms": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+            "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/serve-index/node_modules/setprototypeof": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+            "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/serve-index/node_modules/statuses": {
+            "version": "1.5.0",
+            "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+            "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-string": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz",
-            "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==",
+        "node_modules/serve-static": {
+            "version": "1.16.2",
+            "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
+            "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-value-parser": "^4.2.0"
+                "encodeurl": "~2.0.0",
+                "escape-html": "~1.0.3",
+                "parseurl": "~1.3.3",
+                "send": "0.19.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">= 0.8.0"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-timing-functions": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz",
-            "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==",
+        "node_modules/set-function-length": {
+            "version": "1.2.2",
+            "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+            "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-value-parser": "^4.2.0"
+                "define-data-property": "^1.1.4",
+                "es-errors": "^1.3.0",
+                "function-bind": "^1.1.2",
+                "get-intrinsic": "^1.2.4",
+                "gopd": "^1.0.1",
+                "has-property-descriptors": "^1.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-unicode": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz",
-            "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==",
+        "node_modules/set-function-name": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+            "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserslist": "^4.21.4",
-                "postcss-value-parser": "^4.2.0"
+                "define-data-property": "^1.1.4",
+                "es-errors": "^1.3.0",
+                "functions-have-names": "^1.2.3",
+                "has-property-descriptors": "^1.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-url": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz",
-            "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==",
+        "node_modules/set-proto": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz",
+            "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "normalize-url": "^6.0.1",
-                "postcss-value-parser": "^4.2.0"
+                "dunder-proto": "^1.0.1",
+                "es-errors": "^1.3.0",
+                "es-object-atoms": "^1.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/postcss-normalize-whitespace": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz",
-            "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==",
+        "node_modules/setimmediate": {
+            "version": "1.0.5",
+            "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+            "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "postcss-value-parser": "^4.2.0"
-            },
-            "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/postcss-ordered-values": {
-            "version": "5.1.3",
-            "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz",
-            "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==",
+        "node_modules/setprototypeof": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+            "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/sha.js": {
+            "version": "2.4.11",
+            "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+            "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
             "dev": true,
             "dev": true,
+            "license": "(MIT AND BSD-3-Clause)",
             "dependencies": {
             "dependencies": {
-                "cssnano-utils": "^3.1.0",
-                "postcss-value-parser": "^4.2.0"
-            },
-            "engines": {
-                "node": "^10 || ^12 || >=14.0"
+                "inherits": "^2.0.1",
+                "safe-buffer": "^5.0.1"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "bin": {
+                "sha.js": "bin.js"
             }
         },
             }
         },
-        "node_modules/postcss-reduce-initial": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz",
-            "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==",
+        "node_modules/shallow-clone": {
+            "version": "3.0.1",
+            "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+            "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "browserslist": "^4.21.4",
-                "caniuse-api": "^3.0.0"
+                "kind-of": "^6.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/postcss-reduce-transforms": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz",
-            "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==",
+        "node_modules/shebang-command": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+            "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-value-parser": "^4.2.0"
+                "shebang-regex": "^3.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+                "node": ">=8"
             }
         },
             }
         },
-        "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==",
+        "node_modules/shebang-regex": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+            "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "cssesc": "^3.0.0",
-                "util-deprecate": "^1.0.2"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=4"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/postcss-svgo": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz",
-            "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==",
+        "node_modules/shell-quote": {
+            "version": "1.8.3",
+            "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
+            "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "postcss-value-parser": "^4.2.0",
-                "svgo": "^2.7.0"
-            },
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
+                "node": ">= 0.4"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/postcss-unique-selectors": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz",
-            "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==",
+        "node_modules/shellwords": {
+            "version": "0.1.1",
+            "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+            "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
             "dev": true,
             "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/side-channel": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+            "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "postcss-selector-parser": "^6.0.5"
+                "es-errors": "^1.3.0",
+                "object-inspect": "^1.13.3",
+                "side-channel-list": "^1.0.0",
+                "side-channel-map": "^1.0.1",
+                "side-channel-weakmap": "^1.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": "^10 || ^12 || >=14.0"
+                "node": ">= 0.4"
             },
             },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/postcss-value-parser": {
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
-            "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
-            "dev": true
-        },
-        "node_modules/prelude-ls": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-            "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
-            "dev": true,
+        "node_modules/side-channel-list": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+            "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+            "license": "MIT",
+            "dependencies": {
+                "es-errors": "^1.3.0",
+                "object-inspect": "^1.13.3"
+            },
             "engines": {
             "engines": {
-                "node": ">= 0.8.0"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/pretty-format": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
-            "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
-            "dev": true,
+        "node_modules/side-channel-map": {
+            "version": "1.0.1",
+            "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+            "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@jest/schemas": "^29.6.3",
-                "ansi-styles": "^5.0.0",
-                "react-is": "^18.0.0"
+                "call-bound": "^1.0.2",
+                "es-errors": "^1.3.0",
+                "get-intrinsic": "^1.2.5",
+                "object-inspect": "^1.13.3"
             },
             "engines": {
             },
             "engines": {
-                "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/pretty-format/node_modules/ansi-styles": {
-            "version": "5.2.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
-            "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
-            "dev": true,
+        "node_modules/side-channel-weakmap": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+            "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+            "license": "MIT",
+            "dependencies": {
+                "call-bound": "^1.0.2",
+                "es-errors": "^1.3.0",
+                "get-intrinsic": "^1.2.5",
+                "object-inspect": "^1.13.3",
+                "side-channel-map": "^1.0.1"
+            },
             "engines": {
             "engines": {
-                "node": ">=10"
+                "node": ">= 0.4"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/pretty-format/node_modules/react-is": {
-            "version": "18.2.0",
-            "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
-            "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
-            "dev": true
+        "node_modules/siginfo": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+            "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
+            "dev": true,
+            "license": "ISC"
         },
         },
-        "node_modules/pretty-time": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz",
-            "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==",
+        "node_modules/signal-exit": {
+            "version": "3.0.7",
+            "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+            "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+            "dev": true,
+            "license": "ISC"
+        },
+        "node_modules/slash": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+            "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=4"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/process": {
-            "version": "0.11.10",
-            "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
-            "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+        "node_modules/sockjs": {
+            "version": "0.3.24",
+            "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
+            "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">= 0.6.0"
+            "license": "MIT",
+            "dependencies": {
+                "faye-websocket": "^0.11.3",
+                "uuid": "^8.3.2",
+                "websocket-driver": "^0.7.4"
             }
         },
             }
         },
-        "node_modules/process-nextick-args": {
+        "node_modules/source-list-map": {
             "version": "2.0.1",
             "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
-            "dev": true
+            "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
+            "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/prompts": {
-            "version": "2.4.2",
-            "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
-            "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+        "node_modules/source-map": {
+            "version": "0.6.1",
+            "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+            "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "kleur": "^3.0.3",
-                "sisteransi": "^1.0.5"
-            },
+            "license": "BSD-3-Clause",
             "engines": {
             "engines": {
-                "node": ">= 6"
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "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/source-map-js": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+            "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+            "dev": true,
+            "license": "BSD-3-Clause",
+            "engines": {
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "node_modules/prop-types-extra": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
-            "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
+        "node_modules/source-map-support": {
+            "version": "0.5.21",
+            "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+            "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "react-is": "^16.3.2",
-                "warning": "^4.0.0"
-            },
-            "peerDependencies": {
-                "react": ">=0.14.0"
+                "buffer-from": "^1.0.0",
+                "source-map": "^0.6.0"
             }
         },
             }
         },
-        "node_modules/property-expr": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
-            "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
-        },
-        "node_modules/proxy-addr": {
-            "version": "2.0.7",
-            "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
-            "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+        "node_modules/spdy": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
+            "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "forwarded": "0.2.0",
-                "ipaddr.js": "1.9.1"
+                "debug": "^4.1.0",
+                "handle-thing": "^2.0.0",
+                "http-deceiver": "^1.2.7",
+                "select-hose": "^2.0.0",
+                "spdy-transport": "^3.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 0.10"
+                "node": ">=6.0.0"
             }
         },
             }
         },
-        "node_modules/proxy-addr/node_modules/ipaddr.js": {
-            "version": "1.9.1",
-            "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
-            "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+        "node_modules/spdy-transport": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
+            "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">= 0.10"
+            "license": "MIT",
+            "dependencies": {
+                "debug": "^4.1.0",
+                "detect-node": "^2.0.4",
+                "hpack.js": "^2.1.6",
+                "obuf": "^1.1.2",
+                "readable-stream": "^3.0.6",
+                "wbuf": "^1.7.3"
             }
         },
             }
         },
-        "node_modules/proxy-from-env": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
-            "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
-            "dev": true
-        },
-        "node_modules/psl": {
-            "version": "1.9.0",
-            "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
-            "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
-            "dev": true
-        },
-        "node_modules/public-encrypt": {
-            "version": "4.0.3",
-            "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
-            "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
+        "node_modules/spdy-transport/node_modules/readable-stream": {
+            "version": "3.6.2",
+            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+            "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "bn.js": "^4.1.0",
-                "browserify-rsa": "^4.0.0",
-                "create-hash": "^1.1.0",
-                "parse-asn1": "^5.0.0",
-                "randombytes": "^2.0.1",
-                "safe-buffer": "^5.1.2"
+                "inherits": "^2.0.3",
+                "string_decoder": "^1.1.1",
+                "util-deprecate": "^1.0.1"
+            },
+            "engines": {
+                "node": ">= 6"
             }
         },
             }
         },
-        "node_modules/public-encrypt/node_modules/bn.js": {
-            "version": "4.12.0",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-            "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-            "dev": true
-        },
-        "node_modules/punycode": {
-            "version": "1.4.1",
-            "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-            "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
-            "dev": true
+        "node_modules/stable": {
+            "version": "0.1.8",
+            "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
+            "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
+            "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "node_modules/pure-rand": {
-            "version": "6.0.4",
-            "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz",
-            "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==",
+        "node_modules/stackback": {
+            "version": "0.0.2",
+            "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+            "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
             "dev": true,
             "dev": true,
-            "funding": [
-                {
-                    "type": "individual",
-                    "url": "https://github.com/sponsors/dubzzz"
-                },
-                {
-                    "type": "opencollective",
-                    "url": "https://opencollective.com/fast-check"
-                }
-            ]
+            "license": "MIT"
         },
         },
-        "node_modules/pusher-js": {
-            "version": "8.3.0",
-            "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.3.0.tgz",
-            "integrity": "sha512-6GohP06WlVeomAQQe9qWh1IDzd3+InluWt+ZUOcecVK1SEQkg6a8uYVsvxSJm7cbccfmHhE0jDkmhKIhue8vmA==",
-            "dependencies": {
-                "tweetnacl": "^1.0.3"
+        "node_modules/statuses": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+            "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
             }
         },
             }
         },
-        "node_modules/qs": {
-            "version": "6.11.2",
-            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
-            "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
+        "node_modules/std-env": {
+            "version": "3.9.0",
+            "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
+            "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/stop-iteration-iterator": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
+            "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "side-channel": "^1.0.4"
+                "es-errors": "^1.3.0",
+                "internal-slot": "^1.1.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=0.6"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "node_modules/querystring-es3": {
-            "version": "0.2.1",
-            "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
-            "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==",
+        "node_modules/stream-browserify": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
+            "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">=0.4.x"
+            "license": "MIT",
+            "dependencies": {
+                "inherits": "~2.0.1",
+                "readable-stream": "^2.0.2"
             }
         },
             }
         },
-        "node_modules/querystringify": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-            "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
-            "dev": true
-        },
-        "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==",
+        "node_modules/stream-http": {
+            "version": "2.8.3",
+            "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
+            "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
             "dev": true,
             "dev": true,
-            "funding": [
-                {
-                    "type": "github",
-                    "url": "https://github.com/sponsors/feross"
-                },
-                {
-                    "type": "patreon",
-                    "url": "https://www.patreon.com/feross"
-                },
-                {
-                    "type": "consulting",
-                    "url": "https://feross.org/support"
-                }
-            ]
+            "license": "MIT",
+            "dependencies": {
+                "builtin-status-codes": "^3.0.0",
+                "inherits": "^2.0.1",
+                "readable-stream": "^2.3.6",
+                "to-arraybuffer": "^1.0.0",
+                "xtend": "^4.0.0"
+            }
         },
         },
-        "node_modules/randombytes": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
-            "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+        "node_modules/string_decoder": {
+            "version": "1.3.0",
+            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+            "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "safe-buffer": "^5.1.0"
+                "safe-buffer": "~5.2.0"
             }
         },
             }
         },
-        "node_modules/randomfill": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
-            "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+        "node_modules/string-width": {
+            "version": "4.2.3",
+            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "randombytes": "^2.0.5",
-                "safe-buffer": "^5.1.0"
+                "emoji-regex": "^8.0.0",
+                "is-fullwidth-code-point": "^3.0.0",
+                "strip-ansi": "^6.0.1"
+            },
+            "engines": {
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/range-parser": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-            "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+        "node_modules/string-width-cjs": {
+            "name": "string-width",
+            "version": "4.2.3",
+            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "emoji-regex": "^8.0.0",
+                "is-fullwidth-code-point": "^3.0.0",
+                "strip-ansi": "^6.0.1"
+            },
             "engines": {
             "engines": {
-                "node": ">= 0.6"
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/raw-body": {
-            "version": "2.5.1",
-            "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
-            "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+        "node_modules/string.prototype.matchall": {
+            "version": "4.0.12",
+            "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
+            "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "bytes": "3.1.2",
-                "http-errors": "2.0.0",
-                "iconv-lite": "0.4.24",
-                "unpipe": "1.0.0"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.3",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.6",
+                "es-errors": "^1.3.0",
+                "es-object-atoms": "^1.0.0",
+                "get-intrinsic": "^1.2.6",
+                "gopd": "^1.2.0",
+                "has-symbols": "^1.1.0",
+                "internal-slot": "^1.1.0",
+                "regexp.prototype.flags": "^1.5.3",
+                "set-function-name": "^2.0.2",
+                "side-channel": "^1.1.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 0.8"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/raw-body/node_modules/bytes": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
-            "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+        "node_modules/string.prototype.repeat": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
+            "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
             "dev": true,
             "dev": true,
-            "engines": {
-                "node": ">= 0.8"
+            "license": "MIT",
+            "dependencies": {
+                "define-properties": "^1.1.3",
+                "es-abstract": "^1.17.5"
             }
         },
             }
         },
-        "node_modules/react": {
-            "version": "18.2.0",
-            "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
-            "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+        "node_modules/string.prototype.trim": {
+            "version": "1.2.10",
+            "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz",
+            "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "loose-envify": "^1.1.0"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.2",
+                "define-data-property": "^1.1.4",
+                "define-properties": "^1.2.1",
+                "es-abstract": "^1.23.5",
+                "es-object-atoms": "^1.0.0",
+                "has-property-descriptors": "^1.0.2"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=0.10.0"
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/react-bootstrap": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz",
-            "integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==",
+        "node_modules/string.prototype.trimend": {
+            "version": "1.0.9",
+            "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz",
+            "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/runtime": "^7.21.0",
-                "@restart/hooks": "^0.4.9",
-                "@restart/ui": "^1.6.3",
-                "@types/react-transition-group": "^4.4.5",
-                "classnames": "^2.3.2",
-                "dom-helpers": "^5.2.1",
-                "invariant": "^2.2.4",
-                "prop-types": "^15.8.1",
-                "prop-types-extra": "^1.1.0",
-                "react-transition-group": "^4.4.5",
-                "uncontrollable": "^7.2.1",
-                "warning": "^4.0.3"
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.2",
+                "define-properties": "^1.2.1",
+                "es-object-atoms": "^1.0.0"
             },
             },
-            "peerDependencies": {
-                "@types/react": ">=16.14.8",
-                "react": ">=16.14.0",
-                "react-dom": ">=16.14.0"
+            "engines": {
+                "node": ">= 0.4"
             },
             },
-            "peerDependenciesMeta": {
-                "@types/react": {
-                    "optional": true
-                }
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "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==",
+        "node_modules/string.prototype.trimstart": {
+            "version": "1.0.8",
+            "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+            "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "loose-envify": "^1.1.0",
-                "scheduler": "^0.23.0"
+                "call-bind": "^1.0.7",
+                "define-properties": "^1.2.1",
+                "es-object-atoms": "^1.0.0"
             },
             },
-            "peerDependencies": {
-                "react": "^18.2.0"
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "node_modules/react-fast-compare": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
-            "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
-        },
-        "node_modules/react-helmet": {
-            "version": "6.1.0",
-            "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz",
-            "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==",
+        "node_modules/strip-ansi": {
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "object-assign": "^4.1.1",
-                "prop-types": "^15.7.2",
-                "react-fast-compare": "^3.1.1",
-                "react-side-effect": "^2.1.0"
+                "ansi-regex": "^5.0.1"
             },
             },
-            "peerDependencies": {
-                "react": ">=16.3.0"
+            "engines": {
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/react-helmet/node_modules/react-fast-compare": {
-            "version": "3.2.2",
-            "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
-            "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
-        },
-        "node_modules/react-i18next": {
-            "version": "13.2.2",
-            "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-13.2.2.tgz",
-            "integrity": "sha512-+nFUkbRByFwnrfDcYqvzBuaeZb+nACHx+fAWN/pZMddWOCJH5hoc21+Sa/N/Lqi6ne6/9wC/qRGOoQhJa6IkEQ==",
+        "node_modules/strip-ansi-cjs": {
+            "name": "strip-ansi",
+            "version": "6.0.1",
+            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@babel/runtime": "^7.22.5",
-                "html-parse-stringify": "^3.0.1"
-            },
-            "peerDependencies": {
-                "i18next": ">= 23.2.3",
-                "react": ">= 16.8.0"
+                "ansi-regex": "^5.0.1"
             },
             },
-            "peerDependenciesMeta": {
-                "react-dom": {
-                    "optional": true
-                },
-                "react-native": {
-                    "optional": true
-                }
+            "engines": {
+                "node": ">=8"
             }
         },
             }
         },
-        "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/strip-bom": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+            "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
         },
         },
-        "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/strip-final-newline": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+            "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=6"
+            }
         },
         },
-        "node_modules/react-resize-detector": {
-            "version": "8.1.0",
-            "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-8.1.0.tgz",
-            "integrity": "sha512-S7szxlaIuiy5UqLhLL1KY3aoyGHbZzsTpYal9eYMwCyKqoqoVLCmIgAgNyIM1FhnP2KyBygASJxdhejrzjMb+w==",
+        "node_modules/strip-indent": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+            "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "lodash": "^4.17.21"
+                "min-indent": "^1.0.0"
             },
             },
-            "peerDependencies": {
-                "react": "^16.0.0 || ^17.0.0 || ^18.0.0",
-                "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
+            "engines": {
+                "node": ">=8"
             }
         },
             }
         },
-        "node_modules/react-router": {
-            "version": "6.15.0",
-            "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz",
-            "integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==",
-            "dependencies": {
-                "@remix-run/router": "1.8.0"
-            },
+        "node_modules/strip-json-comments": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+            "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+            "dev": true,
+            "license": "MIT",
             "engines": {
             "engines": {
-                "node": ">=14.0.0"
+                "node": ">=8"
             },
             },
-            "peerDependencies": {
-                "react": ">=16.8"
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
             }
         },
             }
         },
-        "node_modules/react-router-bootstrap": {
-            "version": "0.26.2",
-            "resolved": "https://registry.npmjs.org/react-router-bootstrap/-/react-router-bootstrap-0.26.2.tgz",
-            "integrity": "sha512-YlpI9Xi+Uqp6zFAUO8D/wu6P8mr1ujqq+0V5MhJG1kx9dr/95fAMoGk4J+/CsysOkwtR3tYSac4DDWmHwXvC8w==",
+        "node_modules/strip-literal": {
+            "version": "3.0.0",
+            "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz",
+            "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "prop-types": "^15.7.2"
+                "js-tokens": "^9.0.1"
             },
             },
-            "peerDependencies": {
-                "react": ">=16.13.1",
-                "react-router-dom": ">=6.0.0"
+            "funding": {
+                "url": "https://github.com/sponsors/antfu"
             }
         },
             }
         },
-        "node_modules/react-router-dom": {
-            "version": "6.15.0",
-            "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz",
-            "integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==",
+        "node_modules/strip-literal/node_modules/js-tokens": {
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+            "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/style-loader": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz",
+            "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "@remix-run/router": "1.8.0",
-                "react-router": "6.15.0"
+                "loader-utils": "^2.0.0",
+                "schema-utils": "^3.0.0"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=14.0.0"
+                "node": ">= 10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "react": ">=16.8",
-                "react-dom": ">=16.8"
-            }
-        },
-        "node_modules/react-side-effect": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz",
-            "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==",
-            "peerDependencies": {
-                "react": "^16.3.0 || ^17.0.0 || ^18.0.0"
+                "webpack": "^4.0.0 || ^5.0.0"
             }
         },
             }
         },
-        "node_modules/react-smooth": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.3.tgz",
-            "integrity": "sha512-yl4y3XiMorss7ayF5QnBiSprig0+qFHui8uh7Hgg46QX5O+aRMRKlfGGNGLHno35JkQSvSYY8eCWkBfHfrSHfg==",
+        "node_modules/style-loader/node_modules/schema-utils": {
+            "version": "3.3.0",
+            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+            "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "fast-equals": "^5.0.0",
-                "react-transition-group": "2.9.0"
+                "@types/json-schema": "^7.0.8",
+                "ajv": "^6.12.5",
+                "ajv-keywords": "^3.5.2"
             },
             },
-            "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"
+            "engines": {
+                "node": ">= 10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
             }
         },
             }
         },
-        "node_modules/react-smooth/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/style-mod": {
+            "version": "4.1.2",
+            "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
+            "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
+            "license": "MIT"
         },
         },
-        "node_modules/react-smooth/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==",
+        "node_modules/stylehacks": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
+            "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "dom-helpers": "^3.4.0",
-                "loose-envify": "^1.4.0",
-                "prop-types": "^15.6.2",
-                "react-lifecycles-compat": "^3.0.4"
+                "browserslist": "^4.21.4",
+                "postcss-selector-parser": "^6.0.4"
+            },
+            "engines": {
+                "node": "^10 || ^12 || >=14.0"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "react": ">=15.0.0",
-                "react-dom": ">=15.0.0"
+                "postcss": "^8.2.15"
             }
         },
             }
         },
-        "node_modules/react-transition-group": {
-            "version": "4.4.5",
-            "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
-            "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+        "node_modules/sucrase": {
+            "version": "3.35.0",
+            "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
+            "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+            "dev": true,
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "@babel/runtime": "^7.5.5",
-                "dom-helpers": "^5.0.1",
-                "loose-envify": "^1.4.0",
-                "prop-types": "^15.6.2"
+                "@jridgewell/gen-mapping": "^0.3.2",
+                "commander": "^4.0.0",
+                "glob": "^10.3.10",
+                "lines-and-columns": "^1.1.6",
+                "mz": "^2.7.0",
+                "pirates": "^4.0.1",
+                "ts-interface-checker": "^0.1.9"
             },
             },
-            "peerDependencies": {
-                "react": ">=16.6.0",
-                "react-dom": ">=16.6.0"
+            "bin": {
+                "sucrase": "bin/sucrase",
+                "sucrase-node": "bin/sucrase-node"
+            },
+            "engines": {
+                "node": ">=16 || 14 >=14.17"
             }
         },
             }
         },
-        "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==",
+        "node_modules/sucrase/node_modules/brace-expansion": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+            "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "pify": "^2.3.0"
+                "balanced-match": "^1.0.0"
             }
         },
             }
         },
-        "node_modules/readable-stream": {
-            "version": "2.3.8",
-            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
-            "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+        "node_modules/sucrase/node_modules/commander": {
+            "version": "4.1.1",
+            "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+            "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+            "dev": true,
+            "license": "MIT",
+            "peer": true,
+            "engines": {
+                "node": ">= 6"
+            }
+        },
+        "node_modules/sucrase/node_modules/glob": {
+            "version": "10.4.5",
+            "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+            "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "core-util-is": "~1.0.0",
-                "inherits": "~2.0.3",
-                "isarray": "~1.0.0",
-                "process-nextick-args": "~2.0.0",
-                "safe-buffer": "~5.1.1",
-                "string_decoder": "~1.1.1",
-                "util-deprecate": "~1.0.1"
+                "foreground-child": "^3.1.0",
+                "jackspeak": "^3.1.2",
+                "minimatch": "^9.0.4",
+                "minipass": "^7.1.2",
+                "package-json-from-dist": "^1.0.0",
+                "path-scurry": "^1.11.1"
+            },
+            "bin": {
+                "glob": "dist/esm/bin.mjs"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
             }
         },
             }
         },
-        "node_modules/readable-stream/node_modules/safe-buffer": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-            "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-            "dev": true
-        },
-        "node_modules/readable-stream/node_modules/string_decoder": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-            "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-            "dev": true,
-            "dependencies": {
-                "safe-buffer": "~5.1.0"
-            }
-        },
-        "node_modules/readdirp": {
-            "version": "3.6.0",
-            "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-            "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+        "node_modules/sucrase/node_modules/minimatch": {
+            "version": "9.0.5",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+            "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
             "dev": true,
             "dev": true,
+            "license": "ISC",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "picomatch": "^2.2.1"
-            },
-            "engines": {
-                "node": ">=8.10.0"
-            }
-        },
-        "node_modules/recharts": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.8.0.tgz",
-            "integrity": "sha512-nciXqQDh3aW8abhwUlA4EBOBusRHLNiKHfpRZiG/yjups1x+auHb2zWPuEcTn/IMiN47vVMMuF8Sr+vcQJtsmw==",
-            "dependencies": {
-                "classnames": "^2.2.5",
-                "eventemitter3": "^4.0.1",
-                "lodash": "^4.17.19",
-                "react-is": "^16.10.2",
-                "react-resize-detector": "^8.0.4",
-                "react-smooth": "^2.0.2",
-                "recharts-scale": "^0.4.4",
-                "reduce-css-calc": "^2.1.8",
-                "victory-vendor": "^36.6.8"
+                "brace-expansion": "^2.0.1"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=12"
-            },
-            "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/rechoir": {
-            "version": "0.7.1",
-            "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
-            "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
-            "dev": true,
-            "dependencies": {
-                "resolve": "^1.9.0"
+                "node": ">=16 || 14 >=14.17"
             },
             },
-            "engines": {
-                "node": ">= 0.10"
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
             }
         },
             }
         },
-        "node_modules/redent": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
-            "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+        "node_modules/supports-color": {
+            "version": "7.2.0",
+            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "indent-string": "^4.0.0",
-                "strip-indent": "^3.0.0"
+                "has-flag": "^4.0.0"
             },
             "engines": {
                 "node": ">=8"
             }
         },
             },
             "engines": {
                 "node": ">=8"
             }
         },
-        "node_modules/reduce-css-calc": {
-            "version": "2.1.8",
-            "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
-            "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
-            "dependencies": {
-                "css-unit-converter": "^1.1.1",
-                "postcss-value-parser": "^3.3.0"
-            }
-        },
-        "node_modules/reduce-css-calc/node_modules/postcss-value-parser": {
-            "version": "3.3.1",
-            "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-            "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
-        },
-        "node_modules/reflect.getprototypeof": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz",
-            "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==",
+        "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==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1",
-                "globalthis": "^1.0.3",
-                "which-builtin-type": "^1.1.3"
-            },
+            "license": "MIT",
             "engines": {
                 "node": ">= 0.4"
             },
             "engines": {
                 "node": ">= 0.4"
             },
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
                 "url": "https://github.com/sponsors/ljharb"
             }
         },
-        "node_modules/regenerate": {
-            "version": "1.4.2",
-            "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
-            "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
-            "dev": true
-        },
-        "node_modules/regenerate-unicode-properties": {
-            "version": "10.1.0",
-            "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz",
-            "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==",
+        "node_modules/svgo": {
+            "version": "2.8.0",
+            "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
+            "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "regenerate": "^1.4.2"
+                "@trysound/sax": "0.2.0",
+                "commander": "^7.2.0",
+                "css-select": "^4.1.3",
+                "css-tree": "^1.1.3",
+                "csso": "^4.2.0",
+                "picocolors": "^1.0.0",
+                "stable": "^0.1.8"
             },
             },
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/regenerator-runtime": {
-            "version": "0.14.0",
-            "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
-            "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
-        },
-        "node_modules/regenerator-transform": {
-            "version": "0.15.2",
-            "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
-            "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
-            "dev": true,
-            "dependencies": {
-                "@babel/runtime": "^7.8.4"
-            }
-        },
-        "node_modules/regex-parser": {
-            "version": "2.2.11",
-            "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz",
-            "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==",
-            "dev": true
-        },
-        "node_modules/regexp.prototype.flags": {
-            "version": "1.5.2",
-            "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
-            "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.6",
-                "define-properties": "^1.2.1",
-                "es-errors": "^1.3.0",
-                "set-function-name": "^2.0.1"
+            "bin": {
+                "svgo": "bin/svgo"
             },
             "engines": {
             },
             "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
+                "node": ">=10.13.0"
             }
         },
             }
         },
-        "node_modules/regexpu-core": {
-            "version": "5.3.2",
-            "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz",
-            "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==",
+        "node_modules/symbol-tree": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+            "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
             "dev": true,
             "dev": true,
-            "dependencies": {
-                "@babel/regjsgen": "^0.8.0",
-                "regenerate": "^1.4.2",
-                "regenerate-unicode-properties": "^10.1.0",
-                "regjsparser": "^0.9.1",
-                "unicode-match-property-ecmascript": "^2.0.0",
-                "unicode-match-property-value-ecmascript": "^2.1.0"
-            },
-            "engines": {
-                "node": ">=4"
-            }
+            "license": "MIT"
         },
         },
-        "node_modules/regjsparser": {
-            "version": "0.9.1",
-            "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
-            "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==",
+        "node_modules/tailwindcss": {
+            "version": "3.4.17",
+            "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
+            "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "jsesc": "~0.5.0"
+                "@alloc/quick-lru": "^5.2.0",
+                "arg": "^5.0.2",
+                "chokidar": "^3.6.0",
+                "didyoumean": "^1.2.2",
+                "dlv": "^1.1.3",
+                "fast-glob": "^3.3.2",
+                "glob-parent": "^6.0.2",
+                "is-glob": "^4.0.3",
+                "jiti": "^1.21.6",
+                "lilconfig": "^3.1.3",
+                "micromatch": "^4.0.8",
+                "normalize-path": "^3.0.0",
+                "object-hash": "^3.0.0",
+                "picocolors": "^1.1.1",
+                "postcss": "^8.4.47",
+                "postcss-import": "^15.1.0",
+                "postcss-js": "^4.0.1",
+                "postcss-load-config": "^4.0.2",
+                "postcss-nested": "^6.2.0",
+                "postcss-selector-parser": "^6.1.2",
+                "resolve": "^1.22.8",
+                "sucrase": "^3.35.0"
             },
             "bin": {
             },
             "bin": {
-                "regjsparser": "bin/parser"
-            }
-        },
-        "node_modules/regjsparser/node_modules/jsesc": {
-            "version": "0.5.0",
-            "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-            "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
-            "dev": true,
-            "bin": {
-                "jsesc": "bin/jsesc"
-            }
-        },
-        "node_modules/relateurl": {
-            "version": "0.2.7",
-            "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
-            "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.10"
-            }
-        },
-        "node_modules/replace-ext": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
-            "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.10"
-            }
-        },
-        "node_modules/require-directory": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-            "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
-            "dev": true,
+                "tailwind": "lib/cli.js",
+                "tailwindcss": "lib/cli.js"
+            },
             "engines": {
             "engines": {
-                "node": ">=0.10.0"
+                "node": ">=14.0.0"
             }
         },
             }
         },
-        "node_modules/require-from-string": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
-            "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+        "node_modules/tailwindcss/node_modules/lilconfig": {
+            "version": "3.1.3",
+            "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+            "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
             "dev": true,
             "dev": true,
+            "license": "MIT",
+            "peer": true,
             "engines": {
             "engines": {
-                "node": ">=0.10.0"
-            }
-        },
-        "node_modules/requires-port": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-            "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
-            "dev": true
-        },
-        "node_modules/resolve": {
-            "version": "1.22.4",
-            "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
-            "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
-            "dev": true,
-            "dependencies": {
-                "is-core-module": "^2.13.0",
-                "path-parse": "^1.0.7",
-                "supports-preserve-symlinks-flag": "^1.0.0"
-            },
-            "bin": {
-                "resolve": "bin/resolve"
+                "node": ">=14"
             },
             "funding": {
             },
             "funding": {
-                "url": "https://github.com/sponsors/ljharb"
+                "url": "https://github.com/sponsors/antonk52"
             }
         },
             }
         },
-        "node_modules/resolve-cwd": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
-            "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+        "node_modules/tailwindcss/node_modules/postcss-load-config": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz",
+            "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==",
             "dev": true,
             "dev": true,
+            "funding": [
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/postcss/"
+                },
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/ai"
+                }
+            ],
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "resolve-from": "^5.0.0"
+                "lilconfig": "^3.0.0",
+                "yaml": "^2.3.4"
             },
             "engines": {
             },
             "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/resolve-cwd/node_modules/resolve-from": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
-            "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/resolve-from": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-            "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-            "dev": true,
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/resolve-url-loader": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz",
-            "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==",
-            "dev": true,
-            "dependencies": {
-                "adjust-sourcemap-loader": "^4.0.0",
-                "convert-source-map": "^1.7.0",
-                "loader-utils": "^2.0.0",
-                "postcss": "^8.2.14",
-                "source-map": "0.6.1"
-            },
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/resolve.exports": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
-            "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==",
-            "dev": true,
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/retry": {
-            "version": "0.13.1",
-            "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
-            "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
-            "dev": true,
-            "engines": {
-                "node": ">= 4"
-            }
-        },
-        "node_modules/reusify": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
-            "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-            "dev": true,
-            "engines": {
-                "iojs": ">=1.0.0",
-                "node": ">=0.10.0"
-            }
-        },
-        "node_modules/rimraf": {
-            "version": "3.0.2",
-            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-            "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-            "dev": true,
-            "dependencies": {
-                "glob": "^7.1.3"
-            },
-            "bin": {
-                "rimraf": "bin.js"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/isaacs"
-            }
-        },
-        "node_modules/ripemd160": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
-            "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
-            "dev": true,
-            "dependencies": {
-                "hash-base": "^3.0.0",
-                "inherits": "^2.0.1"
-            }
-        },
-        "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==",
-            "dev": true,
-            "funding": [
-                {
-                    "type": "github",
-                    "url": "https://github.com/sponsors/feross"
-                },
-                {
-                    "type": "patreon",
-                    "url": "https://www.patreon.com/feross"
-                },
-                {
-                    "type": "consulting",
-                    "url": "https://feross.org/support"
-                }
-            ],
-            "dependencies": {
-                "queue-microtask": "^1.2.2"
-            }
-        },
-        "node_modules/safe-array-concat": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz",
-            "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.2.1",
-                "has-symbols": "^1.0.3",
-                "isarray": "^2.0.5"
-            },
-            "engines": {
-                "node": ">=0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/safe-array-concat/node_modules/isarray": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-            "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-            "dev": true
-        },
-        "node_modules/safe-buffer": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-            "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-            "dev": true,
-            "funding": [
-                {
-                    "type": "github",
-                    "url": "https://github.com/sponsors/feross"
-                },
-                {
-                    "type": "patreon",
-                    "url": "https://www.patreon.com/feross"
-                },
-                {
-                    "type": "consulting",
-                    "url": "https://feross.org/support"
-                }
-            ]
-        },
-        "node_modules/safe-regex-test": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
-            "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.1.3",
-                "is-regex": "^1.1.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/safer-buffer": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-            "dev": true
-        },
-        "node_modules/sass": {
-            "version": "1.66.1",
-            "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz",
-            "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==",
-            "dev": true,
-            "dependencies": {
-                "chokidar": ">=3.0.0 <4.0.0",
-                "immutable": "^4.0.0",
-                "source-map-js": ">=0.6.2 <2.0.0"
-            },
-            "bin": {
-                "sass": "sass.js"
-            },
-            "engines": {
-                "node": ">=14.0.0"
-            }
-        },
-        "node_modules/sass-loader": {
-            "version": "13.3.2",
-            "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz",
-            "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==",
-            "dev": true,
-            "dependencies": {
-                "neo-async": "^2.6.2"
-            },
-            "engines": {
-                "node": ">= 14.15.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
+                "node": ">= 14"
             },
             "peerDependencies": {
             },
             "peerDependencies": {
-                "fibers": ">= 3.1.0",
-                "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
-                "sass": "^1.3.0",
-                "sass-embedded": "*",
-                "webpack": "^5.0.0"
+                "postcss": ">=8.0.9",
+                "ts-node": ">=9.0.0"
             },
             "peerDependenciesMeta": {
             },
             "peerDependenciesMeta": {
-                "fibers": {
-                    "optional": true
-                },
-                "node-sass": {
-                    "optional": true
-                },
-                "sass": {
-                    "optional": true
-                },
-                "sass-embedded": {
+                "postcss": {
                     "optional": true
                     "optional": true
-                }
-            }
-        },
-        "node_modules/saxes": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
-            "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
-            "dev": true,
-            "dependencies": {
-                "xmlchars": "^2.2.0"
-            },
-            "engines": {
-                "node": ">=v12.22.7"
-            }
-        },
-        "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/schema-utils": {
-            "version": "2.7.1",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
-            "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
-            "dev": true,
-            "dependencies": {
-                "@types/json-schema": "^7.0.5",
-                "ajv": "^6.12.4",
-                "ajv-keywords": "^3.5.2"
-            },
-            "engines": {
-                "node": ">= 8.9.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            }
-        },
-        "node_modules/select-hose": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
-            "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==",
-            "dev": true
-        },
-        "node_modules/selfsigned": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz",
-            "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==",
-            "dev": true,
-            "dependencies": {
-                "node-forge": "^1"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/semver": {
-            "version": "6.3.1",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-            "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-            "dev": true,
-            "bin": {
-                "semver": "bin/semver.js"
-            }
-        },
-        "node_modules/send": {
-            "version": "0.18.0",
-            "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
-            "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
-            "dev": true,
-            "dependencies": {
-                "debug": "2.6.9",
-                "depd": "2.0.0",
-                "destroy": "1.2.0",
-                "encodeurl": "~1.0.2",
-                "escape-html": "~1.0.3",
-                "etag": "~1.8.1",
-                "fresh": "0.5.2",
-                "http-errors": "2.0.0",
-                "mime": "1.6.0",
-                "ms": "2.1.3",
-                "on-finished": "2.4.1",
-                "range-parser": "~1.2.1",
-                "statuses": "2.0.1"
-            },
-            "engines": {
-                "node": ">= 0.8.0"
-            }
-        },
-        "node_modules/send/node_modules/debug": {
-            "version": "2.6.9",
-            "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-            "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-            "dev": true,
-            "dependencies": {
-                "ms": "2.0.0"
-            }
-        },
-        "node_modules/send/node_modules/debug/node_modules/ms": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-            "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-            "dev": true
-        },
-        "node_modules/send/node_modules/ms": {
-            "version": "2.1.3",
-            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-            "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-            "dev": true
-        },
-        "node_modules/serialize-javascript": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
-            "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
-            "dev": true,
-            "dependencies": {
-                "randombytes": "^2.1.0"
-            }
-        },
-        "node_modules/serve-index": {
-            "version": "1.9.1",
-            "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
-            "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
-            "dev": true,
-            "dependencies": {
-                "accepts": "~1.3.4",
-                "batch": "0.6.1",
-                "debug": "2.6.9",
-                "escape-html": "~1.0.3",
-                "http-errors": "~1.6.2",
-                "mime-types": "~2.1.17",
-                "parseurl": "~1.3.2"
-            },
-            "engines": {
-                "node": ">= 0.8.0"
-            }
-        },
-        "node_modules/serve-index/node_modules/debug": {
-            "version": "2.6.9",
-            "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-            "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-            "dev": true,
-            "dependencies": {
-                "ms": "2.0.0"
-            }
-        },
-        "node_modules/serve-index/node_modules/depd": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
-            "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.6"
-            }
-        },
-        "node_modules/serve-index/node_modules/http-errors": {
-            "version": "1.6.3",
-            "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
-            "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
-            "dev": true,
-            "dependencies": {
-                "depd": "~1.1.2",
-                "inherits": "2.0.3",
-                "setprototypeof": "1.1.0",
-                "statuses": ">= 1.4.0 < 2"
-            },
-            "engines": {
-                "node": ">= 0.6"
-            }
-        },
-        "node_modules/serve-index/node_modules/inherits": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-            "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
-            "dev": true
-        },
-        "node_modules/serve-index/node_modules/ms": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-            "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-            "dev": true
-        },
-        "node_modules/serve-index/node_modules/setprototypeof": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
-            "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
-            "dev": true
-        },
-        "node_modules/serve-index/node_modules/statuses": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
-            "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.6"
-            }
-        },
-        "node_modules/serve-static": {
-            "version": "1.15.0",
-            "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
-            "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
-            "dev": true,
-            "dependencies": {
-                "encodeurl": "~1.0.2",
-                "escape-html": "~1.0.3",
-                "parseurl": "~1.3.3",
-                "send": "0.18.0"
-            },
-            "engines": {
-                "node": ">= 0.8.0"
-            }
-        },
-        "node_modules/set-function-length": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
-            "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
-            "dependencies": {
-                "define-data-property": "^1.1.2",
-                "es-errors": "^1.3.0",
-                "function-bind": "^1.1.2",
-                "get-intrinsic": "^1.2.3",
-                "gopd": "^1.0.1",
-                "has-property-descriptors": "^1.0.1"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            }
-        },
-        "node_modules/set-function-name": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
-            "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
-            "dev": true,
-            "dependencies": {
-                "define-data-property": "^1.1.4",
-                "es-errors": "^1.3.0",
-                "functions-have-names": "^1.2.3",
-                "has-property-descriptors": "^1.0.2"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            }
-        },
-        "node_modules/setimmediate": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
-            "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
-            "dev": true
-        },
-        "node_modules/setprototypeof": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
-            "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
-            "dev": true
-        },
-        "node_modules/sha.js": {
-            "version": "2.4.11",
-            "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
-            "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
-            "dev": true,
-            "dependencies": {
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.0.1"
-            },
-            "bin": {
-                "sha.js": "bin.js"
-            }
-        },
-        "node_modules/shallow-clone": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
-            "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
-            "dev": true,
-            "dependencies": {
-                "kind-of": "^6.0.2"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/shebang-command": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-            "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-            "dev": true,
-            "dependencies": {
-                "shebang-regex": "^3.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/shebang-regex": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-            "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/shell-quote": {
-            "version": "1.8.1",
-            "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
-            "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
-            "dev": true,
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/shellwords": {
-            "version": "0.1.1",
-            "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
-            "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
-            "dev": true
-        },
-        "node_modules/side-channel": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
-            "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
-            "dependencies": {
-                "call-bind": "^1.0.0",
-                "get-intrinsic": "^1.0.2",
-                "object-inspect": "^1.9.0"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/signal-exit": {
-            "version": "3.0.7",
-            "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
-            "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
-            "dev": true
-        },
-        "node_modules/sisteransi": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
-            "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
-            "dev": true
-        },
-        "node_modules/slash": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-            "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/sockjs": {
-            "version": "0.3.24",
-            "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
-            "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==",
-            "dev": true,
-            "dependencies": {
-                "faye-websocket": "^0.11.3",
-                "uuid": "^8.3.2",
-                "websocket-driver": "^0.7.4"
-            }
-        },
-        "node_modules/source-list-map": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
-            "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
-            "dev": true
-        },
-        "node_modules/source-map": {
-            "version": "0.6.1",
-            "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-            "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.10.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==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.10.0"
-            }
-        },
-        "node_modules/source-map-support": {
-            "version": "0.5.21",
-            "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
-            "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
-            "dev": true,
-            "dependencies": {
-                "buffer-from": "^1.0.0",
-                "source-map": "^0.6.0"
-            }
-        },
-        "node_modules/spdy": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
-            "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
-            "dev": true,
-            "dependencies": {
-                "debug": "^4.1.0",
-                "handle-thing": "^2.0.0",
-                "http-deceiver": "^1.2.7",
-                "select-hose": "^2.0.0",
-                "spdy-transport": "^3.0.0"
-            },
-            "engines": {
-                "node": ">=6.0.0"
-            }
-        },
-        "node_modules/spdy-transport": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
-            "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
-            "dev": true,
-            "dependencies": {
-                "debug": "^4.1.0",
-                "detect-node": "^2.0.4",
-                "hpack.js": "^2.1.6",
-                "obuf": "^1.1.2",
-                "readable-stream": "^3.0.6",
-                "wbuf": "^1.7.3"
-            }
-        },
-        "node_modules/spdy-transport/node_modules/readable-stream": {
-            "version": "3.6.2",
-            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-            "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
-            "dev": true,
-            "dependencies": {
-                "inherits": "^2.0.3",
-                "string_decoder": "^1.1.1",
-                "util-deprecate": "^1.0.1"
-            },
-            "engines": {
-                "node": ">= 6"
-            }
-        },
-        "node_modules/sprintf-js": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-            "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
-            "dev": true
-        },
-        "node_modules/stable": {
-            "version": "0.1.8",
-            "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
-            "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
-            "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility",
-            "dev": true
-        },
-        "node_modules/stack-utils": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
-            "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
-            "dev": true,
-            "dependencies": {
-                "escape-string-regexp": "^2.0.0"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/stack-utils/node_modules/escape-string-regexp": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
-            "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/statuses": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
-            "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.8"
-            }
-        },
-        "node_modules/std-env": {
-            "version": "3.4.3",
-            "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.3.tgz",
-            "integrity": "sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==",
-            "dev": true
-        },
-        "node_modules/stop-iteration-iterator": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
-            "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
-            "dev": true,
-            "dependencies": {
-                "internal-slot": "^1.0.4"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            }
-        },
-        "node_modules/stream-browserify": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
-            "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
-            "dev": true,
-            "dependencies": {
-                "inherits": "~2.0.1",
-                "readable-stream": "^2.0.2"
-            }
-        },
-        "node_modules/stream-http": {
-            "version": "2.8.3",
-            "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
-            "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
-            "dev": true,
-            "dependencies": {
-                "builtin-status-codes": "^3.0.0",
-                "inherits": "^2.0.1",
-                "readable-stream": "^2.3.6",
-                "to-arraybuffer": "^1.0.0",
-                "xtend": "^4.0.0"
-            }
-        },
-        "node_modules/string_decoder": {
-            "version": "1.3.0",
-            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
-            "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
-            "dev": true,
-            "dependencies": {
-                "safe-buffer": "~5.2.0"
-            }
-        },
-        "node_modules/string-length": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
-            "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
-            "dev": true,
-            "dependencies": {
-                "char-regex": "^1.0.2",
-                "strip-ansi": "^6.0.0"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/string-width": {
-            "version": "4.2.3",
-            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-            "dev": true,
-            "dependencies": {
-                "emoji-regex": "^8.0.0",
-                "is-fullwidth-code-point": "^3.0.0",
-                "strip-ansi": "^6.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/string.prototype.matchall": {
-            "version": "4.0.9",
-            "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.9.tgz",
-            "integrity": "sha512-6i5hL3MqG/K2G43mWXWgP+qizFW/QH/7kCNN13JrJS5q48FN5IKksLDscexKP3dnmB6cdm9jlNgAsWNLpSykmA==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1",
-                "has-symbols": "^1.0.3",
-                "internal-slot": "^1.0.5",
-                "regexp.prototype.flags": "^1.5.0",
-                "side-channel": "^1.0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/string.prototype.trim": {
-            "version": "1.2.7",
-            "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
-            "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "es-abstract": "^1.20.4"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/string.prototype.trimend": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
-            "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "es-abstract": "^1.20.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/string.prototype.trimstart": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz",
-            "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/strip-ansi": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-            "dev": true,
-            "dependencies": {
-                "ansi-regex": "^5.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/strip-bom": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-            "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
-            "dev": true,
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/strip-final-newline": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
-            "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
-            }
-        },
-        "node_modules/strip-indent": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
-            "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
-            "dev": true,
-            "dependencies": {
-                "min-indent": "^1.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/strip-json-comments": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-            "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
-        "node_modules/style-loader": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz",
-            "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==",
-            "dev": true,
-            "dependencies": {
-                "loader-utils": "^2.0.0",
-                "schema-utils": "^3.0.0"
-            },
-            "engines": {
-                "node": ">= 10.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            },
-            "peerDependencies": {
-                "webpack": "^4.0.0 || ^5.0.0"
-            }
-        },
-        "node_modules/style-loader/node_modules/schema-utils": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-            "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-            "dev": true,
-            "dependencies": {
-                "@types/json-schema": "^7.0.8",
-                "ajv": "^6.12.5",
-                "ajv-keywords": "^3.5.2"
-            },
-            "engines": {
-                "node": ">= 10.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            }
-        },
-        "node_modules/style-mod": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.0.tgz",
-            "integrity": "sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA=="
-        },
-        "node_modules/stylehacks": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
-            "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==",
-            "dev": true,
-            "dependencies": {
-                "browserslist": "^4.21.4",
-                "postcss-selector-parser": "^6.0.4"
-            },
-            "engines": {
-                "node": "^10 || ^12 || >=14.0"
-            },
-            "peerDependencies": {
-                "postcss": "^8.2.15"
-            }
-        },
-        "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==",
-            "dev": true,
-            "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/sucrase/node_modules/commander": {
-            "version": "4.1.1",
-            "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
-            "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
-            "dev": true,
-            "engines": {
-                "node": ">= 6"
-            }
-        },
-        "node_modules/sucrase/node_modules/glob": {
-            "version": "7.1.6",
-            "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-            "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-            "dev": true,
-            "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/supports-color": {
-            "version": "5.5.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-            "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-            "dev": true,
-            "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==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/svgo": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
-            "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
-            "dev": true,
-            "dependencies": {
-                "@trysound/sax": "0.2.0",
-                "commander": "^7.2.0",
-                "css-select": "^4.1.3",
-                "css-tree": "^1.1.3",
-                "csso": "^4.2.0",
-                "picocolors": "^1.0.0",
-                "stable": "^0.1.8"
-            },
-            "bin": {
-                "svgo": "bin/svgo"
-            },
-            "engines": {
-                "node": ">=10.13.0"
-            }
-        },
-        "node_modules/symbol-tree": {
-            "version": "3.2.4",
-            "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
-            "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
-            "dev": true
-        },
-        "node_modules/tailwindcss": {
-            "version": "3.3.3",
-            "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
-            "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
-            "dev": true,
-            "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.2.12",
-                "glob-parent": "^6.0.2",
-                "is-glob": "^4.0.3",
-                "jiti": "^1.18.2",
-                "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/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==",
-            "dev": true,
-            "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/tailwindcss/node_modules/yaml": {
-            "version": "2.3.2",
-            "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz",
-            "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==",
-            "dev": true,
-            "engines": {
-                "node": ">= 14"
-            }
-        },
-        "node_modules/tapable": {
-            "version": "2.2.1",
-            "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
-            "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
-            }
-        },
-        "node_modules/terser": {
-            "version": "5.19.4",
-            "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.4.tgz",
-            "integrity": "sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g==",
-            "dev": true,
-            "dependencies": {
-                "@jridgewell/source-map": "^0.3.3",
-                "acorn": "^8.8.2",
-                "commander": "^2.20.0",
-                "source-map-support": "~0.5.20"
-            },
-            "bin": {
-                "terser": "bin/terser"
-            },
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/terser-webpack-plugin": {
-            "version": "5.3.9",
-            "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz",
-            "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==",
-            "dev": true,
-            "dependencies": {
-                "@jridgewell/trace-mapping": "^0.3.17",
-                "jest-worker": "^27.4.5",
-                "schema-utils": "^3.1.1",
-                "serialize-javascript": "^6.0.1",
-                "terser": "^5.16.8"
-            },
-            "engines": {
-                "node": ">= 10.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            },
-            "peerDependencies": {
-                "webpack": "^5.1.0"
-            },
-            "peerDependenciesMeta": {
-                "@swc/core": {
-                    "optional": true
-                },
-                "esbuild": {
-                    "optional": true
-                },
-                "uglify-js": {
-                    "optional": true
-                }
-            }
-        },
-        "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-            "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-            "dev": true,
-            "dependencies": {
-                "@types/json-schema": "^7.0.8",
-                "ajv": "^6.12.5",
-                "ajv-keywords": "^3.5.2"
-            },
-            "engines": {
-                "node": ">= 10.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            }
-        },
-        "node_modules/terser/node_modules/commander": {
-            "version": "2.20.3",
-            "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-            "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-            "dev": true
-        },
-        "node_modules/test-exclude": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
-            "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
-            "dev": true,
-            "dependencies": {
-                "@istanbuljs/schema": "^0.1.2",
-                "glob": "^7.1.4",
-                "minimatch": "^3.0.4"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/text-table": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-            "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
-            "dev": true
-        },
-        "node_modules/thenify": {
-            "version": "3.3.1",
-            "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
-            "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
-            "dev": true,
-            "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==",
-            "dev": true,
-            "dependencies": {
-                "thenify": ">= 3.1.0 < 4"
-            },
-            "engines": {
-                "node": ">=0.8"
-            }
-        },
-        "node_modules/thunky": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
-            "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
-            "dev": true
-        },
-        "node_modules/timers-browserify": {
-            "version": "2.0.12",
-            "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
-            "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
-            "dev": true,
-            "dependencies": {
-                "setimmediate": "^1.0.4"
-            },
-            "engines": {
-                "node": ">=0.6.0"
-            }
-        },
-        "node_modules/tiny-case": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
-            "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
-        },
-        "node_modules/tiny-warning": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
-            "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
-        },
-        "node_modules/tmpl": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
-            "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
-            "dev": true
-        },
-        "node_modules/to-arraybuffer": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
-            "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==",
-            "dev": true
-        },
-        "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==",
-            "dev": true,
-            "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==",
-            "dev": true,
-            "dependencies": {
-                "is-number": "^7.0.0"
-            },
-            "engines": {
-                "node": ">=8.0"
-            }
-        },
-        "node_modules/toastr": {
-            "version": "2.1.4",
-            "resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz",
-            "integrity": "sha512-LIy77F5n+sz4tefMmFOntcJ6HL0Fv3k1TDnNmFZ0bU/GcvIIfy6eG2v7zQmMiYgaalAiUv75ttFrPn5s0gyqlA==",
-            "dependencies": {
-                "jquery": ">=1.12.0"
-            }
-        },
-        "node_modules/toidentifier": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
-            "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.6"
-            }
-        },
-        "node_modules/toposort": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
-            "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
-        },
-        "node_modules/tough-cookie": {
-            "version": "4.1.3",
-            "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
-            "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
-            "dev": true,
-            "dependencies": {
-                "psl": "^1.1.33",
-                "punycode": "^2.1.1",
-                "universalify": "^0.2.0",
-                "url-parse": "^1.5.3"
-            },
-            "engines": {
-                "node": ">=6"
-            }
-        },
-        "node_modules/tough-cookie/node_modules/punycode": {
-            "version": "2.3.1",
-            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-            "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
-            }
-        },
-        "node_modules/tough-cookie/node_modules/universalify": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
-            "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
-            "dev": true,
-            "engines": {
-                "node": ">= 4.0.0"
-            }
-        },
-        "node_modules/tr46": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
-            "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
-            "dev": true,
-            "dependencies": {
-                "punycode": "^2.1.1"
-            },
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/tr46/node_modules/punycode": {
-            "version": "2.3.1",
-            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-            "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
-            }
-        },
-        "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==",
-            "dev": true
-        },
-        "node_modules/tsconfig-paths": {
-            "version": "3.14.2",
-            "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
-            "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
-            "dev": true,
-            "dependencies": {
-                "@types/json5": "^0.0.29",
-                "json5": "^1.0.2",
-                "minimist": "^1.2.6",
-                "strip-bom": "^3.0.0"
-            }
-        },
-        "node_modules/tsconfig-paths/node_modules/json5": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-            "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-            "dev": true,
-            "dependencies": {
-                "minimist": "^1.2.0"
-            },
-            "bin": {
-                "json5": "lib/cli.js"
-            }
-        },
-        "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/tty-browserify": {
-            "version": "0.0.0",
-            "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
-            "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==",
-            "dev": true
-        },
-        "node_modules/tweetnacl": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
-            "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
-        },
-        "node_modules/type-check": {
-            "version": "0.4.0",
-            "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
-            "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
-            "dev": true,
-            "dependencies": {
-                "prelude-ls": "^1.2.1"
-            },
-            "engines": {
-                "node": ">= 0.8.0"
-            }
-        },
-        "node_modules/type-detect": {
-            "version": "4.0.8",
-            "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
-            "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
-            "dev": true,
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/type-fest": {
-            "version": "0.20.2",
-            "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-            "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
-        "node_modules/type-is": {
-            "version": "1.6.18",
-            "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
-            "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
-            "dev": true,
-            "dependencies": {
-                "media-typer": "0.3.0",
-                "mime-types": "~2.1.24"
-            },
-            "engines": {
-                "node": ">= 0.6"
-            }
-        },
-        "node_modules/typed-array-buffer": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz",
-            "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.2.1",
-                "is-typed-array": "^1.1.10"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            }
-        },
-        "node_modules/typed-array-byte-length": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz",
-            "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "for-each": "^0.3.3",
-                "has-proto": "^1.0.1",
-                "is-typed-array": "^1.1.10"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/typed-array-byte-offset": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz",
-            "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==",
-            "dev": true,
-            "dependencies": {
-                "available-typed-arrays": "^1.0.5",
-                "call-bind": "^1.0.2",
-                "for-each": "^0.3.3",
-                "has-proto": "^1.0.1",
-                "is-typed-array": "^1.1.10"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/typed-array-length": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
-            "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "for-each": "^0.3.3",
-                "is-typed-array": "^1.1.9"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/unbox-primitive": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
-            "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
-            "dev": true,
-            "dependencies": {
-                "call-bind": "^1.0.2",
-                "has-bigints": "^1.0.2",
-                "has-symbols": "^1.0.3",
-                "which-boxed-primitive": "^1.0.2"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/uncontrollable": {
-            "version": "7.2.1",
-            "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
-            "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
-            "dependencies": {
-                "@babel/runtime": "^7.6.3",
-                "@types/react": ">=16.9.11",
-                "invariant": "^2.2.4",
-                "react-lifecycles-compat": "^3.0.4"
-            },
-            "peerDependencies": {
-                "react": ">=15.0.0"
-            }
-        },
-        "node_modules/unicode-canonical-property-names-ecmascript": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
-            "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/unicode-match-property-ecmascript": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
-            "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
-            "dev": true,
-            "dependencies": {
-                "unicode-canonical-property-names-ecmascript": "^2.0.0",
-                "unicode-property-aliases-ecmascript": "^2.0.0"
-            },
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/unicode-match-property-value-ecmascript": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
-            "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
-            "dev": true,
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/unicode-property-aliases-ecmascript": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
-            "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
-            "dev": true,
-            "engines": {
-                "node": ">=4"
-            }
-        },
-        "node_modules/universalify": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
-            "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
-            "dev": true,
-            "engines": {
-                "node": ">= 10.0.0"
-            }
-        },
-        "node_modules/unpipe": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-            "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.8"
-            }
-        },
-        "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==",
-            "dev": true,
-            "funding": [
-                {
-                    "type": "opencollective",
-                    "url": "https://opencollective.com/browserslist"
-                },
-                {
-                    "type": "tidelift",
-                    "url": "https://tidelift.com/funding/github/npm/browserslist"
-                },
-                {
-                    "type": "github",
-                    "url": "https://github.com/sponsors/ai"
-                }
-            ],
-            "dependencies": {
-                "escalade": "^3.1.1",
-                "picocolors": "^1.0.0"
-            },
-            "bin": {
-                "update-browserslist-db": "cli.js"
-            },
-            "peerDependencies": {
-                "browserslist": ">= 4.21.0"
-            }
-        },
-        "node_modules/uri-js": {
-            "version": "4.4.1",
-            "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
-            "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
-            "dev": true,
-            "dependencies": {
-                "punycode": "^2.1.0"
-            }
-        },
-        "node_modules/uri-js/node_modules/punycode": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
-            "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
-            "dev": true,
-            "engines": {
-                "node": ">=6"
-            }
-        },
-        "node_modules/url": {
-            "version": "0.11.1",
-            "resolved": "https://registry.npmjs.org/url/-/url-0.11.1.tgz",
-            "integrity": "sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==",
-            "dev": true,
-            "dependencies": {
-                "punycode": "^1.4.1",
-                "qs": "^6.11.0"
-            }
-        },
-        "node_modules/url-parse": {
-            "version": "1.5.10",
-            "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
-            "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
-            "dev": true,
-            "dependencies": {
-                "querystringify": "^2.1.1",
-                "requires-port": "^1.0.0"
-            }
-        },
-        "node_modules/util": {
-            "version": "0.11.1",
-            "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
-            "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
-            "dev": true,
-            "dependencies": {
-                "inherits": "2.0.3"
-            }
-        },
-        "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==",
-            "dev": true
-        },
-        "node_modules/util/node_modules/inherits": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-            "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
-            "dev": true
-        },
-        "node_modules/utils-merge": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
-            "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.4.0"
-            }
-        },
-        "node_modules/uuid": {
-            "version": "8.3.2",
-            "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
-            "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
-            "dev": true,
-            "bin": {
-                "uuid": "dist/bin/uuid"
-            }
-        },
-        "node_modules/v8-to-istanbul": {
-            "version": "9.2.0",
-            "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz",
-            "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==",
-            "dev": true,
-            "dependencies": {
-                "@jridgewell/trace-mapping": "^0.3.12",
-                "@types/istanbul-lib-coverage": "^2.0.1",
-                "convert-source-map": "^2.0.0"
-            },
-            "engines": {
-                "node": ">=10.12.0"
-            }
-        },
-        "node_modules/v8-to-istanbul/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==",
-            "dev": true
-        },
-        "node_modules/vary": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
-            "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
-            "dev": true,
-            "engines": {
-                "node": ">= 0.8"
-            }
-        },
-        "node_modules/victory-vendor": {
-            "version": "36.6.11",
-            "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.6.11.tgz",
-            "integrity": "sha512-nT8kCiJp8dQh8g991J/R5w5eE2KnO8EAIP0xocWlh9l2okngMWglOPoMZzJvek8Q1KUc4XE/mJxTZnvOB1sTYg==",
-            "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/vm-browserify": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
-            "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
-            "dev": true
-        },
-        "node_modules/void-elements": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
-            "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
-            "engines": {
-                "node": ">=0.10.0"
-            }
-        },
-        "node_modules/vue-style-loader": {
-            "version": "4.1.3",
-            "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
-            "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==",
-            "dev": true,
-            "dependencies": {
-                "hash-sum": "^1.0.2",
-                "loader-utils": "^1.0.2"
-            }
-        },
-        "node_modules/vue-style-loader/node_modules/json5": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-            "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-            "dev": true,
-            "dependencies": {
-                "minimist": "^1.2.0"
-            },
-            "bin": {
-                "json5": "lib/cli.js"
-            }
-        },
-        "node_modules/vue-style-loader/node_modules/loader-utils": {
-            "version": "1.4.2",
-            "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
-            "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
-            "dev": true,
-            "dependencies": {
-                "big.js": "^5.2.2",
-                "emojis-list": "^3.0.0",
-                "json5": "^1.0.1"
-            },
-            "engines": {
-                "node": ">=4.0.0"
-            }
-        },
-        "node_modules/w3c-keyname": {
-            "version": "2.2.8",
-            "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
-            "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
-        },
-        "node_modules/w3c-xmlserializer": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
-            "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
-            "dev": true,
-            "dependencies": {
-                "xml-name-validator": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=14"
-            }
-        },
-        "node_modules/walker": {
-            "version": "1.0.8",
-            "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
-            "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
-            "dev": true,
-            "dependencies": {
-                "makeerror": "1.0.12"
-            }
-        },
-        "node_modules/warning": {
-            "version": "4.0.3",
-            "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
-            "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
-            "dependencies": {
-                "loose-envify": "^1.0.0"
-            }
-        },
-        "node_modules/watchpack": {
-            "version": "2.4.0",
-            "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
-            "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
-            "dev": true,
-            "dependencies": {
-                "glob-to-regexp": "^0.4.1",
-                "graceful-fs": "^4.1.2"
-            },
-            "engines": {
-                "node": ">=10.13.0"
-            }
-        },
-        "node_modules/wbuf": {
-            "version": "1.7.3",
-            "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
-            "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
-            "dev": true,
-            "dependencies": {
-                "minimalistic-assert": "^1.0.0"
-            }
-        },
-        "node_modules/webidl-conversions": {
-            "version": "7.0.0",
-            "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
-            "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
-            "dev": true,
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/webpack": {
-            "version": "5.88.2",
-            "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz",
-            "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==",
-            "dev": true,
-            "dependencies": {
-                "@types/eslint-scope": "^3.7.3",
-                "@types/estree": "^1.0.0",
-                "@webassemblyjs/ast": "^1.11.5",
-                "@webassemblyjs/wasm-edit": "^1.11.5",
-                "@webassemblyjs/wasm-parser": "^1.11.5",
-                "acorn": "^8.7.1",
-                "acorn-import-assertions": "^1.9.0",
-                "browserslist": "^4.14.5",
-                "chrome-trace-event": "^1.0.2",
-                "enhanced-resolve": "^5.15.0",
-                "es-module-lexer": "^1.2.1",
-                "eslint-scope": "5.1.1",
-                "events": "^3.2.0",
-                "glob-to-regexp": "^0.4.1",
-                "graceful-fs": "^4.2.9",
-                "json-parse-even-better-errors": "^2.3.1",
-                "loader-runner": "^4.2.0",
-                "mime-types": "^2.1.27",
-                "neo-async": "^2.6.2",
-                "schema-utils": "^3.2.0",
-                "tapable": "^2.1.1",
-                "terser-webpack-plugin": "^5.3.7",
-                "watchpack": "^2.4.0",
-                "webpack-sources": "^3.2.3"
-            },
-            "bin": {
-                "webpack": "bin/webpack.js"
-            },
-            "engines": {
-                "node": ">=10.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            },
-            "peerDependenciesMeta": {
-                "webpack-cli": {
-                    "optional": true
-                }
-            }
-        },
-        "node_modules/webpack-cli": {
-            "version": "4.10.0",
-            "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
-            "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
-            "dev": true,
-            "dependencies": {
-                "@discoveryjs/json-ext": "^0.5.0",
-                "@webpack-cli/configtest": "^1.2.0",
-                "@webpack-cli/info": "^1.5.0",
-                "@webpack-cli/serve": "^1.7.0",
-                "colorette": "^2.0.14",
-                "commander": "^7.0.0",
-                "cross-spawn": "^7.0.3",
-                "fastest-levenshtein": "^1.0.12",
-                "import-local": "^3.0.2",
-                "interpret": "^2.2.0",
-                "rechoir": "^0.7.0",
-                "webpack-merge": "^5.7.3"
-            },
-            "bin": {
-                "webpack-cli": "bin/cli.js"
-            },
-            "engines": {
-                "node": ">=10.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            },
-            "peerDependencies": {
-                "webpack": "4.x.x || 5.x.x"
-            },
-            "peerDependenciesMeta": {
-                "@webpack-cli/generators": {
-                    "optional": true
-                },
-                "@webpack-cli/migrate": {
-                    "optional": true
-                },
-                "webpack-bundle-analyzer": {
-                    "optional": true
-                },
-                "webpack-dev-server": {
-                    "optional": true
-                }
-            }
-        },
-        "node_modules/webpack-dev-middleware": {
-            "version": "5.3.3",
-            "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
-            "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
-            "dev": true,
-            "dependencies": {
-                "colorette": "^2.0.10",
-                "memfs": "^3.4.3",
-                "mime-types": "^2.1.31",
-                "range-parser": "^1.2.1",
-                "schema-utils": "^4.0.0"
-            },
-            "engines": {
-                "node": ">= 12.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            },
-            "peerDependencies": {
-                "webpack": "^4.0.0 || ^5.0.0"
-            }
-        },
-        "node_modules/webpack-dev-middleware/node_modules/ajv": {
-            "version": "8.12.0",
-            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
-            "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
-            "dev": true,
-            "dependencies": {
-                "fast-deep-equal": "^3.1.1",
-                "json-schema-traverse": "^1.0.0",
-                "require-from-string": "^2.0.2",
-                "uri-js": "^4.2.2"
-            },
-            "funding": {
-                "type": "github",
-                "url": "https://github.com/sponsors/epoberezkin"
-            }
-        },
-        "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
-            "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
-            "dev": true,
-            "dependencies": {
-                "fast-deep-equal": "^3.1.3"
-            },
-            "peerDependencies": {
-                "ajv": "^8.8.2"
-            }
-        },
-        "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
-            "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
-            "dev": true
-        },
-        "node_modules/webpack-dev-middleware/node_modules/schema-utils": {
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
-            "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
-            "dev": true,
-            "dependencies": {
-                "@types/json-schema": "^7.0.9",
-                "ajv": "^8.9.0",
-                "ajv-formats": "^2.1.1",
-                "ajv-keywords": "^5.1.0"
-            },
-            "engines": {
-                "node": ">= 12.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            }
-        },
-        "node_modules/webpack-dev-server": {
-            "version": "4.15.1",
-            "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz",
-            "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==",
-            "dev": true,
-            "dependencies": {
-                "@types/bonjour": "^3.5.9",
-                "@types/connect-history-api-fallback": "^1.3.5",
-                "@types/express": "^4.17.13",
-                "@types/serve-index": "^1.9.1",
-                "@types/serve-static": "^1.13.10",
-                "@types/sockjs": "^0.3.33",
-                "@types/ws": "^8.5.5",
-                "ansi-html-community": "^0.0.8",
-                "bonjour-service": "^1.0.11",
-                "chokidar": "^3.5.3",
-                "colorette": "^2.0.10",
-                "compression": "^1.7.4",
-                "connect-history-api-fallback": "^2.0.0",
-                "default-gateway": "^6.0.3",
-                "express": "^4.17.3",
-                "graceful-fs": "^4.2.6",
-                "html-entities": "^2.3.2",
-                "http-proxy-middleware": "^2.0.3",
-                "ipaddr.js": "^2.0.1",
-                "launch-editor": "^2.6.0",
-                "open": "^8.0.9",
-                "p-retry": "^4.5.0",
-                "rimraf": "^3.0.2",
-                "schema-utils": "^4.0.0",
-                "selfsigned": "^2.1.1",
-                "serve-index": "^1.9.1",
-                "sockjs": "^0.3.24",
-                "spdy": "^4.0.2",
-                "webpack-dev-middleware": "^5.3.1",
-                "ws": "^8.13.0"
-            },
-            "bin": {
-                "webpack-dev-server": "bin/webpack-dev-server.js"
-            },
-            "engines": {
-                "node": ">= 12.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            },
-            "peerDependencies": {
-                "webpack": "^4.37.0 || ^5.0.0"
-            },
-            "peerDependenciesMeta": {
-                "webpack": {
-                    "optional": true
-                },
-                "webpack-cli": {
-                    "optional": true
-                }
-            }
-        },
-        "node_modules/webpack-dev-server/node_modules/ajv": {
-            "version": "8.12.0",
-            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
-            "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
-            "dev": true,
-            "dependencies": {
-                "fast-deep-equal": "^3.1.1",
-                "json-schema-traverse": "^1.0.0",
-                "require-from-string": "^2.0.2",
-                "uri-js": "^4.2.2"
-            },
-            "funding": {
-                "type": "github",
-                "url": "https://github.com/sponsors/epoberezkin"
-            }
-        },
-        "node_modules/webpack-dev-server/node_modules/ajv-keywords": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
-            "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
-            "dev": true,
-            "dependencies": {
-                "fast-deep-equal": "^3.1.3"
-            },
-            "peerDependencies": {
-                "ajv": "^8.8.2"
-            }
-        },
-        "node_modules/webpack-dev-server/node_modules/json-schema-traverse": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
-            "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
-            "dev": true
-        },
-        "node_modules/webpack-dev-server/node_modules/schema-utils": {
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
-            "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
-            "dev": true,
-            "dependencies": {
-                "@types/json-schema": "^7.0.9",
-                "ajv": "^8.9.0",
-                "ajv-formats": "^2.1.1",
-                "ajv-keywords": "^5.1.0"
-            },
-            "engines": {
-                "node": ">= 12.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            }
-        },
-        "node_modules/webpack-merge": {
-            "version": "5.9.0",
-            "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz",
-            "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==",
-            "dev": true,
-            "dependencies": {
-                "clone-deep": "^4.0.1",
-                "wildcard": "^2.0.0"
-            },
-            "engines": {
-                "node": ">=10.0.0"
-            }
-        },
-        "node_modules/webpack-notifier": {
-            "version": "1.15.0",
-            "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.15.0.tgz",
-            "integrity": "sha512-N2V8UMgRB5komdXQRavBsRpw0hPhJq2/SWNOGuhrXpIgRhcMexzkGQysUyGStHLV5hkUlgpRiF7IUXoBqyMmzQ==",
-            "dev": true,
-            "dependencies": {
-                "node-notifier": "^9.0.0",
-                "strip-ansi": "^6.0.0"
-            },
-            "peerDependencies": {
-                "@types/webpack": ">4.41.31"
-            },
-            "peerDependenciesMeta": {
-                "@types/webpack": {
-                    "optional": true
-                }
-            }
-        },
-        "node_modules/webpack-sources": {
-            "version": "1.4.3",
-            "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
-            "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
-            "dev": true,
-            "dependencies": {
-                "source-list-map": "^2.0.0",
-                "source-map": "~0.6.1"
-            }
-        },
-        "node_modules/webpack/node_modules/schema-utils": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-            "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-            "dev": true,
-            "dependencies": {
-                "@types/json-schema": "^7.0.8",
-                "ajv": "^6.12.5",
-                "ajv-keywords": "^3.5.2"
-            },
-            "engines": {
-                "node": ">= 10.13.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/webpack"
-            }
-        },
-        "node_modules/webpack/node_modules/webpack-sources": {
-            "version": "3.2.3",
-            "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
-            "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
-            "dev": true,
-            "engines": {
-                "node": ">=10.13.0"
-            }
-        },
-        "node_modules/webpackbar": {
-            "version": "5.0.2",
-            "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz",
-            "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==",
-            "dev": true,
-            "dependencies": {
-                "chalk": "^4.1.0",
-                "consola": "^2.15.3",
-                "pretty-time": "^1.1.0",
-                "std-env": "^3.0.1"
-            },
-            "engines": {
-                "node": ">=12"
-            },
-            "peerDependencies": {
-                "webpack": "3 || 4 || 5"
-            }
-        },
-        "node_modules/webpackbar/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-            }
-        },
-        "node_modules/webpackbar/node_modules/chalk": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-            "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.1.0",
-                "supports-color": "^7.1.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/chalk?sponsor=1"
-            }
-        },
-        "node_modules/webpackbar/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-            "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/webpackbar/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "node_modules/webpackbar/node_modules/has-flag": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-            "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/webpackbar/node_modules/supports-color": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-            "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-            "dev": true,
-            "dependencies": {
-                "has-flag": "^4.0.0"
-            },
-            "engines": {
-                "node": ">=8"
-            }
-        },
-        "node_modules/websocket-driver": {
-            "version": "0.7.4",
-            "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
-            "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
-            "dev": true,
-            "dependencies": {
-                "http-parser-js": ">=0.5.1",
-                "safe-buffer": ">=5.1.0",
-                "websocket-extensions": ">=0.1.1"
-            },
-            "engines": {
-                "node": ">=0.8.0"
-            }
-        },
-        "node_modules/websocket-extensions": {
-            "version": "0.1.4",
-            "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
-            "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.8.0"
-            }
-        },
-        "node_modules/whatwg-encoding": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
-            "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
-            "dev": true,
-            "dependencies": {
-                "iconv-lite": "0.6.3"
-            },
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/whatwg-encoding/node_modules/iconv-lite": {
-            "version": "0.6.3",
-            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
-            "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
-            "dev": true,
-            "dependencies": {
-                "safer-buffer": ">= 2.1.2 < 3.0.0"
-            },
-            "engines": {
-                "node": ">=0.10.0"
-            }
-        },
-        "node_modules/whatwg-mimetype": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
-            "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
-            "dev": true,
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/whatwg-url": {
-            "version": "11.0.0",
-            "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
-            "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
-            "dev": true,
-            "dependencies": {
-                "tr46": "^3.0.0",
-                "webidl-conversions": "^7.0.0"
-            },
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/which": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-            "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-            "dev": true,
-            "dependencies": {
-                "isexe": "^2.0.0"
-            },
-            "bin": {
-                "node-which": "bin/node-which"
-            },
-            "engines": {
-                "node": ">= 8"
-            }
-        },
-        "node_modules/which-boxed-primitive": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
-            "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
-            "dev": true,
-            "dependencies": {
-                "is-bigint": "^1.0.1",
-                "is-boolean-object": "^1.1.0",
-                "is-number-object": "^1.0.4",
-                "is-string": "^1.0.5",
-                "is-symbol": "^1.0.3"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/which-builtin-type": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz",
-            "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==",
-            "dev": true,
-            "dependencies": {
-                "function.prototype.name": "^1.1.5",
-                "has-tostringtag": "^1.0.0",
-                "is-async-function": "^2.0.0",
-                "is-date-object": "^1.0.5",
-                "is-finalizationregistry": "^1.0.2",
-                "is-generator-function": "^1.0.10",
-                "is-regex": "^1.1.4",
-                "is-weakref": "^1.0.2",
-                "isarray": "^2.0.5",
-                "which-boxed-primitive": "^1.0.2",
-                "which-collection": "^1.0.1",
-                "which-typed-array": "^1.1.9"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/which-builtin-type/node_modules/isarray": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-            "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-            "dev": true
-        },
-        "node_modules/which-collection": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
-            "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
-            "dev": true,
-            "dependencies": {
-                "is-map": "^2.0.1",
-                "is-set": "^2.0.1",
-                "is-weakmap": "^2.0.1",
-                "is-weakset": "^2.0.1"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/which-typed-array": {
-            "version": "1.1.14",
-            "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz",
-            "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==",
-            "dev": true,
-            "dependencies": {
-                "available-typed-arrays": "^1.0.6",
-                "call-bind": "^1.0.5",
-                "for-each": "^0.3.3",
-                "gopd": "^1.0.1",
-                "has-tostringtag": "^1.0.1"
-            },
-            "engines": {
-                "node": ">= 0.4"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/ljharb"
-            }
-        },
-        "node_modules/wildcard": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
-            "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
-            "dev": true
-        },
-        "node_modules/wrap-ansi": {
-            "version": "7.0.0",
-            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-            "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-            "dev": true,
-            "dependencies": {
-                "ansi-styles": "^4.0.0",
-                "string-width": "^4.1.0",
-                "strip-ansi": "^6.0.0"
-            },
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-            }
-        },
-        "node_modules/wrap-ansi/node_modules/ansi-styles": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-            "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-            "dev": true,
-            "dependencies": {
-                "color-convert": "^2.0.1"
-            },
-            "engines": {
-                "node": ">=8"
-            },
-            "funding": {
-                "url": "https://github.com/chalk/ansi-styles?sponsor=1"
-            }
-        },
-        "node_modules/wrap-ansi/node_modules/color-convert": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-            "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-            "dev": true,
-            "dependencies": {
-                "color-name": "~1.1.4"
-            },
-            "engines": {
-                "node": ">=7.0.0"
-            }
-        },
-        "node_modules/wrap-ansi/node_modules/color-name": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-            "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-            "dev": true
-        },
-        "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==",
-            "dev": true
-        },
-        "node_modules/write-file-atomic": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
-            "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
-            "dev": true,
-            "dependencies": {
-                "imurmurhash": "^0.1.4",
-                "signal-exit": "^3.0.7"
-            },
-            "engines": {
-                "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
-            }
-        },
-        "node_modules/ws": {
-            "version": "8.13.0",
-            "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
-            "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
-            "dev": true,
-            "engines": {
-                "node": ">=10.0.0"
-            },
-            "peerDependencies": {
-                "bufferutil": "^4.0.1",
-                "utf-8-validate": ">=5.0.2"
-            },
-            "peerDependenciesMeta": {
-                "bufferutil": {
-                    "optional": true
-                },
-                "utf-8-validate": {
-                    "optional": true
-                }
-            }
-        },
-        "node_modules/xml-name-validator": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
-            "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
-            "dev": true,
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/xmlchars": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
-            "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
-            "dev": true
-        },
-        "node_modules/xtend": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
-            "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
-            "dev": true,
-            "engines": {
-                "node": ">=0.4"
-            }
-        },
-        "node_modules/y18n": {
-            "version": "5.0.8",
-            "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
-            "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
-            "dev": true,
-            "engines": {
-                "node": ">=10"
-            }
-        },
-        "node_modules/yallist": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-            "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-            "dev": true
-        },
-        "node_modules/yaml": {
-            "version": "1.10.2",
-            "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
-            "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
-            "dev": true,
-            "engines": {
-                "node": ">= 6"
-            }
-        },
-        "node_modules/yargs": {
-            "version": "17.7.2",
-            "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
-            "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
-            "dev": true,
-            "dependencies": {
-                "cliui": "^8.0.1",
-                "escalade": "^3.1.1",
-                "get-caller-file": "^2.0.5",
-                "require-directory": "^2.1.1",
-                "string-width": "^4.2.3",
-                "y18n": "^5.0.5",
-                "yargs-parser": "^21.1.1"
-            },
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/yargs-parser": {
-            "version": "21.1.1",
-            "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
-            "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-            "dev": true,
-            "engines": {
-                "node": ">=12"
-            }
-        },
-        "node_modules/yocto-queue": {
-            "version": "0.1.0",
-            "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
-            "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
-            "dev": true,
-            "engines": {
-                "node": ">=10"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        },
-        "node_modules/yup": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/yup/-/yup-1.2.0.tgz",
-            "integrity": "sha512-PPqYKSAXjpRCgLgLKVGPA33v5c/WgEx3wi6NFjIiegz90zSwyMpvTFp/uGcVnnbx6to28pgnzp/q8ih3QRjLMQ==",
-            "dependencies": {
-                "property-expr": "^2.0.5",
-                "tiny-case": "^1.0.3",
-                "toposort": "^2.0.2",
-                "type-fest": "^2.19.0"
-            }
-        },
-        "node_modules/yup/node_modules/type-fest": {
-            "version": "2.19.0",
-            "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
-            "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
-            "engines": {
-                "node": ">=12.20"
-            },
-            "funding": {
-                "url": "https://github.com/sponsors/sindresorhus"
-            }
-        }
-    },
-    "dependencies": {
-        "@aashutoshrathi/word-wrap": {
-            "version": "1.2.6",
-            "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
-            "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
-            "dev": true
-        },
-        "@adobe/css-tools": {
-            "version": "4.3.3",
-            "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz",
-            "integrity": "sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ==",
-            "dev": true
-        },
-        "@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==",
-            "dev": true
-        },
-        "@ampproject/remapping": {
-            "version": "2.2.1",
-            "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
-            "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
-            "dev": true,
-            "requires": {
-                "@jridgewell/gen-mapping": "^0.3.0",
-                "@jridgewell/trace-mapping": "^0.3.9"
-            }
-        },
-        "@babel/code-frame": {
-            "version": "7.23.5",
-            "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
-            "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
-            "dev": true,
-            "requires": {
-                "@babel/highlight": "^7.23.4",
-                "chalk": "^2.4.2"
-            }
-        },
-        "@babel/compat-data": {
-            "version": "7.23.5",
-            "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz",
-            "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==",
-            "dev": true
-        },
-        "@babel/core": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz",
-            "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==",
-            "dev": true,
-            "requires": {
-                "@ampproject/remapping": "^2.2.0",
-                "@babel/code-frame": "^7.23.5",
-                "@babel/generator": "^7.23.6",
-                "@babel/helper-compilation-targets": "^7.23.6",
-                "@babel/helper-module-transforms": "^7.23.3",
-                "@babel/helpers": "^7.23.9",
-                "@babel/parser": "^7.23.9",
-                "@babel/template": "^7.23.9",
-                "@babel/traverse": "^7.23.9",
-                "@babel/types": "^7.23.9",
-                "convert-source-map": "^2.0.0",
-                "debug": "^4.1.0",
-                "gensync": "^1.0.0-beta.2",
-                "json5": "^2.2.3",
-                "semver": "^6.3.1"
-            },
-            "dependencies": {
-                "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==",
-                    "dev": true
-                }
-            }
-        },
-        "@babel/eslint-parser": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.15.tgz",
-            "integrity": "sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg==",
-            "dev": true,
-            "requires": {
-                "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1",
-                "eslint-visitor-keys": "^2.1.0",
-                "semver": "^6.3.1"
-            }
-        },
-        "@babel/generator": {
-            "version": "7.23.6",
-            "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
-            "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.23.6",
-                "@jridgewell/gen-mapping": "^0.3.2",
-                "@jridgewell/trace-mapping": "^0.3.17",
-                "jsesc": "^2.5.1"
-            }
-        },
-        "@babel/helper-annotate-as-pure": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
-            "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.5"
-            }
-        },
-        "@babel/helper-builder-binary-assignment-operator-visitor": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz",
-            "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.15"
-            }
-        },
-        "@babel/helper-compilation-targets": {
-            "version": "7.23.6",
-            "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz",
-            "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==",
-            "dev": true,
-            "requires": {
-                "@babel/compat-data": "^7.23.5",
-                "@babel/helper-validator-option": "^7.23.5",
-                "browserslist": "^4.22.2",
-                "lru-cache": "^5.1.1",
-                "semver": "^6.3.1"
-            }
-        },
-        "@babel/helper-create-class-features-plugin": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz",
-            "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-function-name": "^7.22.5",
-                "@babel/helper-member-expression-to-functions": "^7.22.15",
-                "@babel/helper-optimise-call-expression": "^7.22.5",
-                "@babel/helper-replace-supers": "^7.22.9",
-                "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
-                "@babel/helper-split-export-declaration": "^7.22.6",
-                "semver": "^6.3.1"
-            }
-        },
-        "@babel/helper-create-regexp-features-plugin": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz",
-            "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "regexpu-core": "^5.3.1",
-                "semver": "^6.3.1"
-            }
-        },
-        "@babel/helper-define-polyfill-provider": {
-            "version": "0.4.2",
-            "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz",
-            "integrity": "sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-compilation-targets": "^7.22.6",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "debug": "^4.1.1",
-                "lodash.debounce": "^4.0.8",
-                "resolve": "^1.14.2"
-            }
-        },
-        "@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==",
-            "dev": true
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@babel/template": "^7.22.15",
-                "@babel/types": "^7.23.0"
-            }
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.5"
-            }
-        },
-        "@babel/helper-member-expression-to-functions": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz",
-            "integrity": "sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.15"
-            }
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.15"
-            }
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@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-optimise-call-expression": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz",
-            "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.5"
-            }
-        },
-        "@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==",
-            "dev": true
-        },
-        "@babel/helper-remap-async-to-generator": {
-            "version": "7.22.9",
-            "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz",
-            "integrity": "sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-wrap-function": "^7.22.9"
-            }
-        },
-        "@babel/helper-replace-supers": {
-            "version": "7.22.9",
-            "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz",
-            "integrity": "sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-member-expression-to-functions": "^7.22.5",
-                "@babel/helper-optimise-call-expression": "^7.22.5"
-            }
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.5"
-            }
-        },
-        "@babel/helper-skip-transparent-expression-wrappers": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz",
-            "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.5"
-            }
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.22.5"
-            }
-        },
-        "@babel/helper-string-parser": {
-            "version": "7.23.4",
-            "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
-            "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
-            "dev": true
-        },
-        "@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==",
-            "dev": true
-        },
-        "@babel/helper-validator-option": {
-            "version": "7.23.5",
-            "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
-            "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
-            "dev": true
-        },
-        "@babel/helper-wrap-function": {
-            "version": "7.22.10",
-            "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz",
-            "integrity": "sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-function-name": "^7.22.5",
-                "@babel/template": "^7.22.5",
-                "@babel/types": "^7.22.10"
-            }
-        },
-        "@babel/helpers": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz",
-            "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==",
-            "dev": true,
-            "requires": {
-                "@babel/template": "^7.23.9",
-                "@babel/traverse": "^7.23.9",
-                "@babel/types": "^7.23.9"
-            }
-        },
-        "@babel/highlight": {
-            "version": "7.23.4",
-            "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
-            "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-validator-identifier": "^7.22.20",
-                "chalk": "^2.4.2",
-                "js-tokens": "^4.0.0"
-            }
-        },
-        "@babel/parser": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
-            "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
-            "dev": true
-        },
-        "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz",
-            "integrity": "sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz",
-            "integrity": "sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
-                "@babel/plugin-transform-optional-chaining": "^7.22.15"
-            }
-        },
-        "@babel/plugin-proposal-object-rest-spread": {
-            "version": "7.20.7",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz",
-            "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==",
-            "dev": true,
-            "requires": {
-                "@babel/compat-data": "^7.20.5",
-                "@babel/helper-compilation-targets": "^7.20.7",
-                "@babel/helper-plugin-utils": "^7.20.2",
-                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-                "@babel/plugin-transform-parameters": "^7.20.7"
-            }
-        },
-        "@babel/plugin-proposal-private-property-in-object": {
-            "version": "7.21.0-placeholder-for-preset-env.2",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
-            "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
-            "dev": true,
-            "requires": {}
-        },
-        "@babel/plugin-syntax-async-generators": {
-            "version": "7.8.4",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
-            "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            }
-        },
-        "@babel/plugin-syntax-bigint": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
-            "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            }
-        },
-        "@babel/plugin-syntax-class-properties": {
-            "version": "7.12.13",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
-            "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.12.13"
-            }
-        },
-        "@babel/plugin-syntax-class-static-block": {
-            "version": "7.14.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
-            "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.14.5"
-            }
-        },
-        "@babel/plugin-syntax-dynamic-import": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
-            "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            }
-        },
-        "@babel/plugin-syntax-export-namespace-from": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
-            "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.3"
-            }
-        },
-        "@babel/plugin-syntax-import-assertions": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz",
-            "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-syntax-import-attributes": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz",
-            "integrity": "sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-syntax-import-meta": {
-            "version": "7.10.4",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
-            "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.10.4"
-            }
-        },
-        "@babel/plugin-syntax-json-strings": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
-            "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            }
-        },
-        "@babel/plugin-syntax-jsx": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz",
-            "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-syntax-logical-assignment-operators": {
-            "version": "7.10.4",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
-            "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.10.4"
-            }
-        },
-        "@babel/plugin-syntax-nullish-coalescing-operator": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
-            "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            }
-        },
-        "@babel/plugin-syntax-numeric-separator": {
-            "version": "7.10.4",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
-            "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.10.4"
-            }
-        },
-        "@babel/plugin-syntax-object-rest-spread": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
-            "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            }
-        },
-        "@babel/plugin-syntax-optional-catch-binding": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
-            "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            }
-        },
-        "@babel/plugin-syntax-optional-chaining": {
-            "version": "7.8.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
-            "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.8.0"
-            }
-        },
-        "@babel/plugin-syntax-private-property-in-object": {
-            "version": "7.14.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
-            "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.14.5"
-            }
-        },
-        "@babel/plugin-syntax-top-level-await": {
-            "version": "7.14.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
-            "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.14.5"
-            }
-        },
-        "@babel/plugin-syntax-typescript": {
-            "version": "7.23.3",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz",
-            "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-syntax-unicode-sets-regex": {
-            "version": "7.18.6",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
-            "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-regexp-features-plugin": "^7.18.6",
-                "@babel/helper-plugin-utils": "^7.18.6"
-            }
-        },
-        "@babel/plugin-transform-arrow-functions": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz",
-            "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-async-generator-functions": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz",
-            "integrity": "sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-remap-async-to-generator": "^7.22.9",
-                "@babel/plugin-syntax-async-generators": "^7.8.4"
-            }
-        },
-        "@babel/plugin-transform-async-to-generator": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz",
-            "integrity": "sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-module-imports": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-remap-async-to-generator": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-block-scoped-functions": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz",
-            "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-block-scoping": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz",
-            "integrity": "sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-class-properties": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz",
-            "integrity": "sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-class-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-class-static-block": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.11.tgz",
-            "integrity": "sha512-GMM8gGmqI7guS/llMFk1bJDkKfn3v3C4KHK9Yg1ey5qcHcOlKb0QvcMrgzvxo+T03/4szNh5lghY+fEC98Kq9g==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-class-features-plugin": "^7.22.11",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-class-static-block": "^7.14.5"
-            }
-        },
-        "@babel/plugin-transform-classes": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz",
-            "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-compilation-targets": "^7.22.15",
-                "@babel/helper-environment-visitor": "^7.22.5",
-                "@babel/helper-function-name": "^7.22.5",
-                "@babel/helper-optimise-call-expression": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-replace-supers": "^7.22.9",
-                "@babel/helper-split-export-declaration": "^7.22.6",
-                "globals": "^11.1.0"
-            }
-        },
-        "@babel/plugin-transform-computed-properties": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz",
-            "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/template": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-destructuring": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz",
-            "integrity": "sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-dotall-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz",
-            "integrity": "sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-duplicate-keys": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz",
-            "integrity": "sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-dynamic-import": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.11.tgz",
-            "integrity": "sha512-g/21plo58sfteWjaO0ZNVb+uEOkJNjAaHhbejrnBmu011l/eNDScmkbjCC3l4FKb10ViaGU4aOkFznSu2zRHgA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-dynamic-import": "^7.8.3"
-            }
-        },
-        "@babel/plugin-transform-exponentiation-operator": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz",
-            "integrity": "sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-export-namespace-from": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.11.tgz",
-            "integrity": "sha512-xa7aad7q7OiT8oNZ1mU7NrISjlSkVdMbNxn9IuLZyL9AJEhs1Apba3I+u5riX1dIkdptP5EKDG5XDPByWxtehw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
-            }
-        },
-        "@babel/plugin-transform-for-of": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz",
-            "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-function-name": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz",
-            "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-compilation-targets": "^7.22.5",
-                "@babel/helper-function-name": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-json-strings": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.11.tgz",
-            "integrity": "sha512-CxT5tCqpA9/jXFlme9xIBCc5RPtdDq3JpkkhgHQqtDdiTnTI0jtZ0QzXhr5DILeYifDPp2wvY2ad+7+hLMW5Pw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-json-strings": "^7.8.3"
-            }
-        },
-        "@babel/plugin-transform-literals": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz",
-            "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-logical-assignment-operators": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.11.tgz",
-            "integrity": "sha512-qQwRTP4+6xFCDV5k7gZBF3C31K34ut0tbEcTKxlX/0KXxm9GLcO14p570aWxFvVzx6QAfPgq7gaeIHXJC8LswQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
-            }
-        },
-        "@babel/plugin-transform-member-expression-literals": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz",
-            "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-modules-amd": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz",
-            "integrity": "sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-module-transforms": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-modules-commonjs": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz",
-            "integrity": "sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-module-transforms": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-simple-access": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-modules-systemjs": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.11.tgz",
-            "integrity": "sha512-rIqHmHoMEOhI3VkVf5jQ15l539KrwhzqcBO6wdCNWPWc/JWt9ILNYNUssbRpeq0qWns8svuw8LnMNCvWBIJ8wA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-hoist-variables": "^7.22.5",
-                "@babel/helper-module-transforms": "^7.22.9",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-validator-identifier": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-modules-umd": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz",
-            "integrity": "sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-module-transforms": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-named-capturing-groups-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz",
-            "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-new-target": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz",
-            "integrity": "sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-nullish-coalescing-operator": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.11.tgz",
-            "integrity": "sha512-YZWOw4HxXrotb5xsjMJUDlLgcDXSfO9eCmdl1bgW4+/lAGdkjaEvOnQ4p5WKKdUgSzO39dgPl0pTnfxm0OAXcg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
-            }
-        },
-        "@babel/plugin-transform-numeric-separator": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.11.tgz",
-            "integrity": "sha512-3dzU4QGPsILdJbASKhF/V2TVP+gJya1PsueQCxIPCEcerqF21oEcrob4mzjsp2Py/1nLfF5m+xYNMDpmA8vffg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-numeric-separator": "^7.10.4"
-            }
-        },
-        "@babel/plugin-transform-object-rest-spread": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz",
-            "integrity": "sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q==",
-            "dev": true,
-            "requires": {
-                "@babel/compat-data": "^7.22.9",
-                "@babel/helper-compilation-targets": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-                "@babel/plugin-transform-parameters": "^7.22.15"
-            }
-        },
-        "@babel/plugin-transform-object-super": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz",
-            "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-replace-supers": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-optional-catch-binding": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.11.tgz",
-            "integrity": "sha512-rli0WxesXUeCJnMYhzAglEjLWVDF6ahb45HuprcmQuLidBJFWjNnOzssk2kuc6e33FlLaiZhG/kUIzUMWdBKaQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
-            }
-        },
-        "@babel/plugin-transform-optional-chaining": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz",
-            "integrity": "sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
-                "@babel/plugin-syntax-optional-chaining": "^7.8.3"
-            }
-        },
-        "@babel/plugin-transform-parameters": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz",
-            "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-private-methods": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz",
-            "integrity": "sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-class-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-private-property-in-object": {
-            "version": "7.22.11",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.11.tgz",
-            "integrity": "sha512-sSCbqZDBKHetvjSwpyWzhuHkmW5RummxJBVbYLkGkaiTOWGxml7SXt0iWa03bzxFIx7wOj3g/ILRd0RcJKBeSQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-create-class-features-plugin": "^7.22.11",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
-            }
-        },
-        "@babel/plugin-transform-property-literals": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz",
-            "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-react-display-name": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz",
-            "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-react-jsx": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz",
-            "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-module-imports": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/plugin-syntax-jsx": "^7.22.5",
-                "@babel/types": "^7.22.15"
-            }
-        },
-        "@babel/plugin-transform-react-jsx-development": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz",
-            "integrity": "sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==",
-            "dev": true,
-            "requires": {
-                "@babel/plugin-transform-react-jsx": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-react-pure-annotations": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.22.5.tgz",
-            "integrity": "sha512-gP4k85wx09q+brArVinTXhWiyzLl9UpmGva0+mWyKxk6JZequ05x3eUcIUE+FyttPKJFRRVtAvQaJ6YF9h1ZpA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-annotate-as-pure": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-regenerator": {
-            "version": "7.22.10",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.10.tgz",
-            "integrity": "sha512-F28b1mDt8KcT5bUyJc/U9nwzw6cV+UmTeRlXYIl2TNqMMJif0Jeey9/RQ3C4NOd2zp0/TRsDns9ttj2L523rsw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "regenerator-transform": "^0.15.2"
-            }
-        },
-        "@babel/plugin-transform-reserved-words": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz",
-            "integrity": "sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-runtime": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.22.15.tgz",
-            "integrity": "sha512-tEVLhk8NRZSmwQ0DJtxxhTrCht1HVo8VaMzYT4w6lwyKBuHsgoioAUA7/6eT2fRfc5/23fuGdlwIxXhRVgWr4g==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-module-imports": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "babel-plugin-polyfill-corejs2": "^0.4.5",
-                "babel-plugin-polyfill-corejs3": "^0.8.3",
-                "babel-plugin-polyfill-regenerator": "^0.5.2",
-                "semver": "^6.3.1"
-            }
-        },
-        "@babel/plugin-transform-shorthand-properties": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz",
-            "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-spread": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz",
-            "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-sticky-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz",
-            "integrity": "sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-template-literals": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz",
-            "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-typeof-symbol": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz",
-            "integrity": "sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-unicode-escapes": {
-            "version": "7.22.10",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.10.tgz",
-            "integrity": "sha512-lRfaRKGZCBqDlRU3UIFovdp9c9mEvlylmpod0/OatICsSfuQ9YFthRo1tpTkGsklEefZdqlEFdY4A2dwTb6ohg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-unicode-property-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz",
-            "integrity": "sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-unicode-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz",
-            "integrity": "sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/plugin-transform-unicode-sets-regex": {
-            "version": "7.22.5",
-            "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz",
-            "integrity": "sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-create-regexp-features-plugin": "^7.22.5",
-                "@babel/helper-plugin-utils": "^7.22.5"
-            }
-        },
-        "@babel/preset-env": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.22.15.tgz",
-            "integrity": "sha512-tZFHr54GBkHk6hQuVA8w4Fmq+MSPsfvMG0vPnOYyTnJpyfMqybL8/MbNCPRT9zc2KBO2pe4tq15g6Uno4Jpoag==",
-            "dev": true,
-            "requires": {
-                "@babel/compat-data": "^7.22.9",
-                "@babel/helper-compilation-targets": "^7.22.15",
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-validator-option": "^7.22.15",
-                "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.22.15",
-                "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.22.15",
-                "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
-                "@babel/plugin-syntax-async-generators": "^7.8.4",
-                "@babel/plugin-syntax-class-properties": "^7.12.13",
-                "@babel/plugin-syntax-class-static-block": "^7.14.5",
-                "@babel/plugin-syntax-dynamic-import": "^7.8.3",
-                "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
-                "@babel/plugin-syntax-import-assertions": "^7.22.5",
-                "@babel/plugin-syntax-import-attributes": "^7.22.5",
-                "@babel/plugin-syntax-import-meta": "^7.10.4",
-                "@babel/plugin-syntax-json-strings": "^7.8.3",
-                "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
-                "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
-                "@babel/plugin-syntax-numeric-separator": "^7.10.4",
-                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-                "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
-                "@babel/plugin-syntax-optional-chaining": "^7.8.3",
-                "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
-                "@babel/plugin-syntax-top-level-await": "^7.14.5",
-                "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
-                "@babel/plugin-transform-arrow-functions": "^7.22.5",
-                "@babel/plugin-transform-async-generator-functions": "^7.22.15",
-                "@babel/plugin-transform-async-to-generator": "^7.22.5",
-                "@babel/plugin-transform-block-scoped-functions": "^7.22.5",
-                "@babel/plugin-transform-block-scoping": "^7.22.15",
-                "@babel/plugin-transform-class-properties": "^7.22.5",
-                "@babel/plugin-transform-class-static-block": "^7.22.11",
-                "@babel/plugin-transform-classes": "^7.22.15",
-                "@babel/plugin-transform-computed-properties": "^7.22.5",
-                "@babel/plugin-transform-destructuring": "^7.22.15",
-                "@babel/plugin-transform-dotall-regex": "^7.22.5",
-                "@babel/plugin-transform-duplicate-keys": "^7.22.5",
-                "@babel/plugin-transform-dynamic-import": "^7.22.11",
-                "@babel/plugin-transform-exponentiation-operator": "^7.22.5",
-                "@babel/plugin-transform-export-namespace-from": "^7.22.11",
-                "@babel/plugin-transform-for-of": "^7.22.15",
-                "@babel/plugin-transform-function-name": "^7.22.5",
-                "@babel/plugin-transform-json-strings": "^7.22.11",
-                "@babel/plugin-transform-literals": "^7.22.5",
-                "@babel/plugin-transform-logical-assignment-operators": "^7.22.11",
-                "@babel/plugin-transform-member-expression-literals": "^7.22.5",
-                "@babel/plugin-transform-modules-amd": "^7.22.5",
-                "@babel/plugin-transform-modules-commonjs": "^7.22.15",
-                "@babel/plugin-transform-modules-systemjs": "^7.22.11",
-                "@babel/plugin-transform-modules-umd": "^7.22.5",
-                "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5",
-                "@babel/plugin-transform-new-target": "^7.22.5",
-                "@babel/plugin-transform-nullish-coalescing-operator": "^7.22.11",
-                "@babel/plugin-transform-numeric-separator": "^7.22.11",
-                "@babel/plugin-transform-object-rest-spread": "^7.22.15",
-                "@babel/plugin-transform-object-super": "^7.22.5",
-                "@babel/plugin-transform-optional-catch-binding": "^7.22.11",
-                "@babel/plugin-transform-optional-chaining": "^7.22.15",
-                "@babel/plugin-transform-parameters": "^7.22.15",
-                "@babel/plugin-transform-private-methods": "^7.22.5",
-                "@babel/plugin-transform-private-property-in-object": "^7.22.11",
-                "@babel/plugin-transform-property-literals": "^7.22.5",
-                "@babel/plugin-transform-regenerator": "^7.22.10",
-                "@babel/plugin-transform-reserved-words": "^7.22.5",
-                "@babel/plugin-transform-shorthand-properties": "^7.22.5",
-                "@babel/plugin-transform-spread": "^7.22.5",
-                "@babel/plugin-transform-sticky-regex": "^7.22.5",
-                "@babel/plugin-transform-template-literals": "^7.22.5",
-                "@babel/plugin-transform-typeof-symbol": "^7.22.5",
-                "@babel/plugin-transform-unicode-escapes": "^7.22.10",
-                "@babel/plugin-transform-unicode-property-regex": "^7.22.5",
-                "@babel/plugin-transform-unicode-regex": "^7.22.5",
-                "@babel/plugin-transform-unicode-sets-regex": "^7.22.5",
-                "@babel/preset-modules": "0.1.6-no-external-plugins",
-                "@babel/types": "^7.22.15",
-                "babel-plugin-polyfill-corejs2": "^0.4.5",
-                "babel-plugin-polyfill-corejs3": "^0.8.3",
-                "babel-plugin-polyfill-regenerator": "^0.5.2",
-                "core-js-compat": "^3.31.0",
-                "semver": "^6.3.1"
-            }
-        },
-        "@babel/preset-modules": {
-            "version": "0.1.6-no-external-plugins",
-            "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
-            "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.0.0",
-                "@babel/types": "^7.4.4",
-                "esutils": "^2.0.2"
-            }
-        },
-        "@babel/preset-react": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.22.15.tgz",
-            "integrity": "sha512-Csy1IJ2uEh/PecCBXXoZGAZBeCATTuePzCSB7dLYWS0vOEj6CNpjxIhW4duWwZodBNueH7QO14WbGn8YyeuN9w==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.22.5",
-                "@babel/helper-validator-option": "^7.22.15",
-                "@babel/plugin-transform-react-display-name": "^7.22.5",
-                "@babel/plugin-transform-react-jsx": "^7.22.15",
-                "@babel/plugin-transform-react-jsx-development": "^7.22.5",
-                "@babel/plugin-transform-react-pure-annotations": "^7.22.5"
-            }
-        },
-        "@babel/regjsgen": {
-            "version": "0.8.0",
-            "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz",
-            "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==",
-            "dev": true
-        },
-        "@babel/runtime": {
-            "version": "7.22.15",
-            "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz",
-            "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==",
-            "requires": {
-                "regenerator-runtime": "^0.14.0"
-            }
-        },
-        "@babel/template": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
-            "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==",
-            "dev": true,
-            "requires": {
-                "@babel/code-frame": "^7.23.5",
-                "@babel/parser": "^7.23.9",
-                "@babel/types": "^7.23.9"
-            }
-        },
-        "@babel/traverse": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
-            "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
-            "dev": true,
-            "requires": {
-                "@babel/code-frame": "^7.23.5",
-                "@babel/generator": "^7.23.6",
-                "@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.9",
-                "@babel/types": "^7.23.9",
-                "debug": "^4.3.1",
-                "globals": "^11.1.0"
-            }
-        },
-        "@babel/types": {
-            "version": "7.23.9",
-            "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
-            "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-string-parser": "^7.23.4",
-                "@babel/helper-validator-identifier": "^7.22.20",
-                "to-fast-properties": "^2.0.0"
-            }
-        },
-        "@bcoe/v8-coverage": {
-            "version": "0.2.3",
-            "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
-            "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
-            "dev": true
-        },
-        "@codemirror/autocomplete": {
-            "version": "6.9.0",
-            "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.9.0.tgz",
-            "integrity": "sha512-Fbwm0V/Wn3BkEJZRhr0hi5BhCo5a7eBL6LYaliPjOSwCyfOpnjXY59HruSxOUNV+1OYer0Tgx1zRNQttjXyDog==",
-            "requires": {
-                "@codemirror/language": "^6.0.0",
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.6.0",
-                "@lezer/common": "^1.0.0"
-            }
-        },
-        "@codemirror/commands": {
-            "version": "6.2.5",
-            "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.5.tgz",
-            "integrity": "sha512-dSi7ow2P2YgPBZflR9AJoaTHvqmeGIgkhignYMd5zK5y6DANTvxKxp6eMEpIDUJkRAaOY/TFZ4jP1ADIO/GLVA==",
-            "requires": {
-                "@codemirror/language": "^6.0.0",
-                "@codemirror/state": "^6.2.0",
-                "@codemirror/view": "^6.0.0",
-                "@lezer/common": "^1.0.0"
-            }
-        },
-        "@codemirror/lang-css": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.2.1.tgz",
-            "integrity": "sha512-/UNWDNV5Viwi/1lpr/dIXJNWiwDxpw13I4pTUAsNxZdg6E0mI2kTQb0P2iHczg1Tu+H4EBgJR+hYhKiHKko7qg==",
-            "requires": {
-                "@codemirror/autocomplete": "^6.0.0",
-                "@codemirror/language": "^6.0.0",
-                "@codemirror/state": "^6.0.0",
-                "@lezer/common": "^1.0.2",
-                "@lezer/css": "^1.0.0"
-            }
-        },
-        "@codemirror/lang-html": {
-            "version": "6.4.6",
-            "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.6.tgz",
-            "integrity": "sha512-E4C8CVupBksXvgLSme/zv31x91g06eZHSph7NczVxZW+/K+3XgJGWNT//2WLzaKSBoxpAjaOi5ZnPU1SHhjh3A==",
-            "requires": {
-                "@codemirror/autocomplete": "^6.0.0",
-                "@codemirror/lang-css": "^6.0.0",
-                "@codemirror/lang-javascript": "^6.0.0",
-                "@codemirror/language": "^6.4.0",
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.17.0",
-                "@lezer/common": "^1.0.0",
-                "@lezer/css": "^1.1.0",
-                "@lezer/html": "^1.3.0"
-            }
-        },
-        "@codemirror/lang-javascript": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.1.tgz",
-            "integrity": "sha512-jlFOXTejVyiQCW3EQwvKH0m99bUYIw40oPmFjSX2VS78yzfe0HELZ+NEo9Yfo1MkGRpGlj3Gnu4rdxV1EnAs5A==",
-            "requires": {
-                "@codemirror/autocomplete": "^6.0.0",
-                "@codemirror/language": "^6.6.0",
-                "@codemirror/lint": "^6.0.0",
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.17.0",
-                "@lezer/common": "^1.0.0",
-                "@lezer/javascript": "^1.0.0"
-            }
-        },
-        "@codemirror/language": {
-            "version": "6.9.0",
-            "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.9.0.tgz",
-            "integrity": "sha512-nFu311/0ne/qGuGCL3oKuktBgzVOaxCHZPZv1tLSZkNjPYxxvkjSbzno3MlErG2tgw1Yw1yF8BxMCegeMXqpiw==",
-            "requires": {
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0",
-                "@lezer/common": "^1.0.0",
-                "@lezer/highlight": "^1.0.0",
-                "@lezer/lr": "^1.0.0",
-                "style-mod": "^4.0.0"
-            }
-        },
-        "@codemirror/lint": {
-            "version": "6.4.1",
-            "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.4.1.tgz",
-            "integrity": "sha512-2Hx945qKX7FBan5/gUdTM8fsMYrNG9clIgEcPXestbLVFAUyQYFAuju/5BMNf/PwgpVaX5pvRm4+ovjbp9D9gQ==",
-            "requires": {
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0",
-                "crelt": "^1.0.5"
-            }
-        },
-        "@codemirror/search": {
-            "version": "6.5.2",
-            "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.2.tgz",
-            "integrity": "sha512-WRihpqd0l9cEh9J3IZe45Yi+Z5MfTsEXnyc3V7qXHP4ZYtIYpGOn+EJ7fyLIkyAm/8S6QIr7/mMISfAadf8zCg==",
-            "requires": {
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0",
-                "crelt": "^1.0.5"
-            }
-        },
-        "@codemirror/state": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.1.tgz",
-            "integrity": "sha512-RupHSZ8+OjNT38zU9fKH2sv+Dnlr8Eb8sl4NOnnqz95mCFTZUaiRP8Xv5MeeaG0px2b8Bnfe7YGwCV3nsBhbuw=="
-        },
-        "@codemirror/theme-one-dark": {
-            "version": "6.1.2",
-            "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
-            "integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
-            "requires": {
-                "@codemirror/language": "^6.0.0",
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0",
-                "@lezer/highlight": "^1.0.0"
-            }
-        },
-        "@codemirror/view": {
-            "version": "6.18.0",
-            "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.18.0.tgz",
-            "integrity": "sha512-T6q1yYAoU+gSWfJFR4ryvDQcyOqS+Mw5RCvh26y0KiNksOOLYhNvdB3BTyLz8vy4fKaYlzbAOyBU7OQPUGHzjQ==",
-            "requires": {
-                "@codemirror/state": "^6.1.4",
-                "style-mod": "^4.1.0",
-                "w3c-keyname": "^2.2.4"
-            }
-        },
-        "@colors/colors": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
-            "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
-            "dev": true,
-            "optional": true
-        },
-        "@discoveryjs/json-ext": {
-            "version": "0.5.7",
-            "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
-            "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
-            "dev": true
-        },
-        "@eslint-community/eslint-utils": {
-            "version": "4.4.0",
-            "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
-            "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
-            "dev": true,
-            "requires": {
-                "eslint-visitor-keys": "^3.3.0"
-            },
-            "dependencies": {
-                "eslint-visitor-keys": {
-                    "version": "3.4.3",
-                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-                    "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
-                    "dev": true
-                }
-            }
-        },
-        "@eslint-community/regexpp": {
-            "version": "4.8.0",
-            "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz",
-            "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==",
-            "dev": true
-        },
-        "@eslint/eslintrc": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz",
-            "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==",
-            "dev": true,
-            "requires": {
-                "ajv": "^6.12.4",
-                "debug": "^4.3.2",
-                "espree": "^9.6.0",
-                "globals": "^13.19.0",
-                "ignore": "^5.2.0",
-                "import-fresh": "^3.2.1",
-                "js-yaml": "^4.1.0",
-                "minimatch": "^3.1.2",
-                "strip-json-comments": "^3.1.1"
-            },
-            "dependencies": {
-                "globals": {
-                    "version": "13.21.0",
-                    "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
-                    "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
-                    "dev": true,
-                    "requires": {
-                        "type-fest": "^0.20.2"
-                    }
-                }
-            }
-        },
-        "@eslint/js": {
-            "version": "8.48.0",
-            "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz",
-            "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==",
-            "dev": true
-        },
-        "@fortawesome/fontawesome-common-types": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz",
-            "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA=="
-        },
-        "@fortawesome/fontawesome-free": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.4.2.tgz",
-            "integrity": "sha512-m5cPn3e2+FDCOgi1mz0RexTUvvQibBebOUlUlW0+YrMjDTPkiJ6VTKukA1GRsvRw+12KyJndNjj0O4AgTxm2Pg=="
-        },
-        "@fortawesome/fontawesome-svg-core": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz",
-            "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==",
-            "requires": {
-                "@fortawesome/fontawesome-common-types": "6.4.2"
-            }
-        },
-        "@fortawesome/free-brands-svg-icons": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.2.tgz",
-            "integrity": "sha512-LKOwJX0I7+mR/cvvf6qIiqcERbdnY+24zgpUSouySml+5w8B4BJOx8EhDR/FTKAu06W12fmUIcv6lzPSwYKGGg==",
-            "requires": {
-                "@fortawesome/fontawesome-common-types": "6.4.2"
-            }
-        },
-        "@fortawesome/free-solid-svg-icons": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.2.tgz",
-            "integrity": "sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==",
-            "requires": {
-                "@fortawesome/fontawesome-common-types": "6.4.2"
-            }
-        },
-        "@fortawesome/react-fontawesome": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
-            "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
-            "requires": {
-                "prop-types": "^15.8.1"
-            }
-        },
-        "@humanwhocodes/config-array": {
-            "version": "0.11.11",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz",
-            "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==",
-            "dev": true,
-            "requires": {
-                "@humanwhocodes/object-schema": "^1.2.1",
-                "debug": "^4.1.1",
-                "minimatch": "^3.0.5"
-            }
-        },
-        "@humanwhocodes/module-importer": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-            "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
-            "dev": true
-        },
-        "@humanwhocodes/object-schema": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
-            "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
-            "dev": true
-        },
-        "@istanbuljs/load-nyc-config": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
-            "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
-            "dev": true,
-            "requires": {
-                "camelcase": "^5.3.1",
-                "find-up": "^4.1.0",
-                "get-package-type": "^0.1.0",
-                "js-yaml": "^3.13.1",
-                "resolve-from": "^5.0.0"
-            },
-            "dependencies": {
-                "argparse": {
-                    "version": "1.0.10",
-                    "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-                    "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-                    "dev": true,
-                    "requires": {
-                        "sprintf-js": "~1.0.2"
-                    }
-                },
-                "find-up": {
-                    "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-                    "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-                    "dev": true,
-                    "requires": {
-                        "locate-path": "^5.0.0",
-                        "path-exists": "^4.0.0"
-                    }
-                },
-                "js-yaml": {
-                    "version": "3.14.1",
-                    "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-                    "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
-                    "dev": true,
-                    "requires": {
-                        "argparse": "^1.0.7",
-                        "esprima": "^4.0.0"
-                    }
-                },
-                "locate-path": {
-                    "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-                    "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-                    "dev": true,
-                    "requires": {
-                        "p-locate": "^4.1.0"
-                    }
-                },
-                "p-limit": {
-                    "version": "2.3.0",
-                    "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-                    "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-                    "dev": true,
-                    "requires": {
-                        "p-try": "^2.0.0"
-                    }
-                },
-                "p-locate": {
-                    "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-                    "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-                    "dev": true,
-                    "requires": {
-                        "p-limit": "^2.2.0"
-                    }
-                },
-                "resolve-from": {
-                    "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
-                    "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
-                    "dev": true
-                }
-            }
-        },
-        "@istanbuljs/schema": {
-            "version": "0.1.3",
-            "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
-            "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
-            "dev": true
-        },
-        "@jest/console": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz",
-            "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
-            "dev": true,
-            "requires": {
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "jest-message-util": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "slash": "^3.0.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "@jest/core": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz",
-            "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
-            "dev": true,
-            "requires": {
-                "@jest/console": "^29.7.0",
-                "@jest/reporters": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "ansi-escapes": "^4.2.1",
-                "chalk": "^4.0.0",
-                "ci-info": "^3.2.0",
-                "exit": "^0.1.2",
-                "graceful-fs": "^4.2.9",
-                "jest-changed-files": "^29.7.0",
-                "jest-config": "^29.7.0",
-                "jest-haste-map": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-regex-util": "^29.6.3",
-                "jest-resolve": "^29.7.0",
-                "jest-resolve-dependencies": "^29.7.0",
-                "jest-runner": "^29.7.0",
-                "jest-runtime": "^29.7.0",
-                "jest-snapshot": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-validate": "^29.7.0",
-                "jest-watcher": "^29.7.0",
-                "micromatch": "^4.0.4",
-                "pretty-format": "^29.7.0",
-                "slash": "^3.0.0",
-                "strip-ansi": "^6.0.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "@jest/environment": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
-            "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
-            "dev": true,
-            "requires": {
-                "@jest/fake-timers": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "jest-mock": "^29.7.0"
-            }
-        },
-        "@jest/expect": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz",
-            "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
-            "dev": true,
-            "requires": {
-                "expect": "^29.7.0",
-                "jest-snapshot": "^29.7.0"
-            }
-        },
-        "@jest/expect-utils": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
-            "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
-            "dev": true,
-            "requires": {
-                "jest-get-type": "^29.6.3"
-            }
-        },
-        "@jest/fake-timers": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
-            "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
-            "dev": true,
-            "requires": {
-                "@jest/types": "^29.6.3",
-                "@sinonjs/fake-timers": "^10.0.2",
-                "@types/node": "*",
-                "jest-message-util": "^29.7.0",
-                "jest-mock": "^29.7.0",
-                "jest-util": "^29.7.0"
-            }
-        },
-        "@jest/globals": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
-            "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
-            "dev": true,
-            "requires": {
-                "@jest/environment": "^29.7.0",
-                "@jest/expect": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "jest-mock": "^29.7.0"
-            }
-        },
-        "@jest/reporters": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz",
-            "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
-            "dev": true,
-            "requires": {
-                "@bcoe/v8-coverage": "^0.2.3",
-                "@jest/console": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@jridgewell/trace-mapping": "^0.3.18",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "collect-v8-coverage": "^1.0.0",
-                "exit": "^0.1.2",
-                "glob": "^7.1.3",
-                "graceful-fs": "^4.2.9",
-                "istanbul-lib-coverage": "^3.0.0",
-                "istanbul-lib-instrument": "^6.0.0",
-                "istanbul-lib-report": "^3.0.0",
-                "istanbul-lib-source-maps": "^4.0.0",
-                "istanbul-reports": "^3.1.3",
-                "jest-message-util": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-worker": "^29.7.0",
-                "slash": "^3.0.0",
-                "string-length": "^4.0.1",
-                "strip-ansi": "^6.0.0",
-                "v8-to-istanbul": "^9.0.1"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "jest-worker": {
-                    "version": "29.7.0",
-                    "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
-                    "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
-                    "dev": true,
-                    "requires": {
-                        "@types/node": "*",
-                        "jest-util": "^29.7.0",
-                        "merge-stream": "^2.0.0",
-                        "supports-color": "^8.0.0"
-                    },
-                    "dependencies": {
-                        "supports-color": {
-                            "version": "8.1.1",
-                            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-                            "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
-                            "dev": true,
-                            "requires": {
-                                "has-flag": "^4.0.0"
-                            }
-                        }
-                    }
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "@jest/schemas": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
-            "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
-            "dev": true,
-            "requires": {
-                "@sinclair/typebox": "^0.27.8"
-            }
-        },
-        "@jest/source-map": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
-            "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
-            "dev": true,
-            "requires": {
-                "@jridgewell/trace-mapping": "^0.3.18",
-                "callsites": "^3.0.0",
-                "graceful-fs": "^4.2.9"
-            }
-        },
-        "@jest/test-result": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz",
-            "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
-            "dev": true,
-            "requires": {
-                "@jest/console": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/istanbul-lib-coverage": "^2.0.0",
-                "collect-v8-coverage": "^1.0.0"
-            }
-        },
-        "@jest/test-sequencer": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
-            "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
-            "dev": true,
-            "requires": {
-                "@jest/test-result": "^29.7.0",
-                "graceful-fs": "^4.2.9",
-                "jest-haste-map": "^29.7.0",
-                "slash": "^3.0.0"
-            }
-        },
-        "@jest/transform": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
-            "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
-            "dev": true,
-            "requires": {
-                "@babel/core": "^7.11.6",
-                "@jest/types": "^29.6.3",
-                "@jridgewell/trace-mapping": "^0.3.18",
-                "babel-plugin-istanbul": "^6.1.1",
-                "chalk": "^4.0.0",
-                "convert-source-map": "^2.0.0",
-                "fast-json-stable-stringify": "^2.1.0",
-                "graceful-fs": "^4.2.9",
-                "jest-haste-map": "^29.7.0",
-                "jest-regex-util": "^29.6.3",
-                "jest-util": "^29.7.0",
-                "micromatch": "^4.0.4",
-                "pirates": "^4.0.4",
-                "slash": "^3.0.0",
-                "write-file-atomic": "^4.0.2"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "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==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "@jest/types": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
-            "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
-            "dev": true,
-            "requires": {
-                "@jest/schemas": "^29.6.3",
-                "@types/istanbul-lib-coverage": "^2.0.0",
-                "@types/istanbul-reports": "^3.0.0",
-                "@types/node": "*",
-                "@types/yargs": "^17.0.8",
-                "chalk": "^4.0.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@jridgewell/set-array": "^1.0.1",
-                "@jridgewell/sourcemap-codec": "^1.4.10",
-                "@jridgewell/trace-mapping": "^0.3.9"
-            }
-        },
-        "@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==",
-            "dev": true
-        },
-        "@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==",
-            "dev": true
-        },
-        "@jridgewell/source-map": {
-            "version": "0.3.5",
-            "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
-            "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
-            "dev": true,
-            "requires": {
-                "@jridgewell/gen-mapping": "^0.3.0",
-                "@jridgewell/trace-mapping": "^0.3.9"
-            }
-        },
-        "@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==",
-            "dev": true
-        },
-        "@jridgewell/trace-mapping": {
-            "version": "0.3.19",
-            "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
-            "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
-            "dev": true,
-            "requires": {
-                "@jridgewell/resolve-uri": "^3.1.0",
-                "@jridgewell/sourcemap-codec": "^1.4.14"
-            }
-        },
-        "@leichtgewicht/ip-codec": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
-            "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
-            "dev": true
-        },
-        "@lezer/common": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.4.tgz",
-            "integrity": "sha512-lZHlk8p67x4aIDtJl6UQrXSOP6oi7dQR3W/geFVrENdA1JDaAJWldnVqVjPMJupbTKbzDfFcePfKttqVidS/dg=="
-        },
-        "@lezer/css": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.3.tgz",
-            "integrity": "sha512-SjSM4pkQnQdJDVc80LYzEaMiNy9txsFbI7HsMgeVF28NdLaAdHNtQ+kB/QqDUzRBV/75NTXjJ/R5IdC8QQGxMg==",
-            "requires": {
-                "@lezer/highlight": "^1.0.0",
-                "@lezer/lr": "^1.0.0"
-            }
-        },
-        "@lezer/highlight": {
-            "version": "1.1.6",
-            "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.6.tgz",
-            "integrity": "sha512-cmSJYa2us+r3SePpRCjN5ymCqCPv+zyXmDl0ciWtVaNiORT/MxM7ZgOMQZADD0o51qOaOg24qc/zBViOIwAjJg==",
-            "requires": {
-                "@lezer/common": "^1.0.0"
-            }
-        },
-        "@lezer/html": {
-            "version": "1.3.6",
-            "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.3.6.tgz",
-            "integrity": "sha512-Kk9HJARZTc0bAnMQUqbtuhFVsB4AnteR2BFUWfZV7L/x1H0aAKz6YabrfJ2gk/BEgjh9L3hg5O4y2IDZRBdzuQ==",
-            "requires": {
-                "@lezer/common": "^1.0.0",
-                "@lezer/highlight": "^1.0.0",
-                "@lezer/lr": "^1.0.0"
-            }
-        },
-        "@lezer/javascript": {
-            "version": "1.4.7",
-            "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.7.tgz",
-            "integrity": "sha512-OVWlK0YEi7HM+9JRWtRkir8qvcg0/kVYg2TAMHlVtl6DU1C9yK1waEOLBMztZsV/axRJxsqfJKhzYz+bxZme5g==",
-            "requires": {
-                "@lezer/highlight": "^1.1.3",
-                "@lezer/lr": "^1.3.0"
-            }
-        },
-        "@lezer/lr": {
-            "version": "1.3.10",
-            "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.10.tgz",
-            "integrity": "sha512-BZfVvf7Re5BIwJHlZXbJn9L8lus5EonxQghyn+ih8Wl36XMFBPTXC0KM0IdUtj9w/diPHsKlXVgL+AlX2jYJ0Q==",
-            "requires": {
-                "@lezer/common": "^1.0.0"
-            }
-        },
-        "@nicolo-ribaudo/eslint-scope-5-internals": {
-            "version": "5.1.1-v1",
-            "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
-            "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==",
-            "dev": true,
-            "requires": {
-                "eslint-scope": "5.1.1"
-            }
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@nodelib/fs.stat": "2.0.5",
-                "run-parallel": "^1.1.9"
-            }
-        },
-        "@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==",
-            "dev": true
-        },
-        "@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==",
-            "dev": true,
-            "requires": {
-                "@nodelib/fs.scandir": "2.1.5",
-                "fastq": "^1.6.0"
-            }
-        },
-        "@popperjs/core": {
-            "version": "2.11.8",
-            "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
-            "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="
-        },
-        "@react-aria/ssr": {
-            "version": "3.7.1",
-            "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.1.tgz",
-            "integrity": "sha512-ovVPSD1WlRpZHt7GI9DqJrWG3OIYS+NXQ9y5HIewMJpSe+jPQmMQfyRmgX4EnvmxSlp0u04Wg/7oItcoSIb/RA==",
-            "requires": {
-                "@swc/helpers": "^0.5.0"
-            }
-        },
-        "@remix-run/router": {
-            "version": "1.8.0",
-            "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.8.0.tgz",
-            "integrity": "sha512-mrfKqIHnSZRyIzBcanNJmVQELTnX+qagEDlcKO90RgRBVOZGSGvZKeDihTRfWcqoDn5N/NkUcwWTccnpN18Tfg=="
-        },
-        "@restart/hooks": {
-            "version": "0.4.11",
-            "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz",
-            "integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==",
-            "requires": {
-                "dequal": "^2.0.3"
-            }
-        },
-        "@restart/ui": {
-            "version": "1.6.6",
-            "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz",
-            "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==",
-            "requires": {
-                "@babel/runtime": "^7.21.0",
-                "@popperjs/core": "^2.11.6",
-                "@react-aria/ssr": "^3.5.0",
-                "@restart/hooks": "^0.4.9",
-                "@types/warning": "^3.0.0",
-                "dequal": "^2.0.3",
-                "dom-helpers": "^5.2.0",
-                "uncontrollable": "^8.0.1",
-                "warning": "^4.0.3"
-            },
-            "dependencies": {
-                "uncontrollable": {
-                    "version": "8.0.4",
-                    "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
-                    "integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
-                    "requires": {}
-                }
-            }
-        },
-        "@sinclair/typebox": {
-            "version": "0.27.8",
-            "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
-            "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
-            "dev": true
-        },
-        "@sinonjs/commons": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
-            "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
-            "dev": true,
-            "requires": {
-                "type-detect": "4.0.8"
-            }
-        },
-        "@sinonjs/fake-timers": {
-            "version": "10.3.0",
-            "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
-            "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
-            "dev": true,
-            "requires": {
-                "@sinonjs/commons": "^3.0.0"
-            }
-        },
-        "@swc/helpers": {
-            "version": "0.5.1",
-            "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz",
-            "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==",
-            "requires": {
-                "tslib": "^2.4.0"
-            }
-        },
-        "@tailwindcss/forms": {
-            "version": "0.5.6",
-            "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz",
-            "integrity": "sha512-Fw+2BJ0tmAwK/w01tEFL5TiaJBX1NLT1/YbWgvm7ws3Qcn11kiXxzNTEQDMs5V3mQemhB56l3u0i9dwdzSQldA==",
-            "dev": true,
-            "requires": {
-                "mini-svg-data-uri": "^1.2.3"
-            }
-        },
-        "@testing-library/dom": {
-            "version": "9.3.4",
-            "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz",
-            "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==",
-            "dev": true,
-            "requires": {
-                "@babel/code-frame": "^7.10.4",
-                "@babel/runtime": "^7.12.5",
-                "@types/aria-query": "^5.0.1",
-                "aria-query": "5.1.3",
-                "chalk": "^4.1.0",
-                "dom-accessibility-api": "^0.5.9",
-                "lz-string": "^1.5.0",
-                "pretty-format": "^27.0.2"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "aria-query": {
-                    "version": "5.1.3",
-                    "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
-                    "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
-                    "dev": true,
-                    "requires": {
-                        "deep-equal": "^2.0.5"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "dom-accessibility-api": {
-                    "version": "0.5.16",
-                    "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
-                    "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "pretty-format": {
-                    "version": "27.5.1",
-                    "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
-                    "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-regex": "^5.0.1",
-                        "ansi-styles": "^5.0.0",
-                        "react-is": "^17.0.1"
-                    },
-                    "dependencies": {
-                        "ansi-styles": {
-                            "version": "5.2.0",
-                            "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
-                            "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
-                            "dev": true
-                        }
-                    }
-                },
-                "react-is": {
-                    "version": "17.0.2",
-                    "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
-                    "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "@testing-library/jest-dom": {
-            "version": "6.4.2",
-            "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz",
-            "integrity": "sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw==",
-            "dev": true,
-            "requires": {
-                "@adobe/css-tools": "^4.3.2",
-                "@babel/runtime": "^7.9.2",
-                "aria-query": "^5.0.0",
-                "chalk": "^3.0.0",
-                "css.escape": "^1.5.1",
-                "dom-accessibility-api": "^0.6.3",
-                "lodash": "^4.17.15",
-                "redent": "^3.0.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "3.0.0",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-                    "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "@testing-library/react": {
-            "version": "14.2.1",
-            "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.1.tgz",
-            "integrity": "sha512-sGdjws32ai5TLerhvzThYFbpnF9XtL65Cjf+gB0Dhr29BGqK+mAeN7SURSdu+eqgET4ANcWoC7FQpkaiGvBr+A==",
-            "dev": true,
-            "requires": {
-                "@babel/runtime": "^7.12.5",
-                "@testing-library/dom": "^9.0.0",
-                "@types/react-dom": "^18.0.0"
-            }
-        },
-        "@tootallnate/once": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
-            "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
-            "dev": true
-        },
-        "@trysound/sax": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
-            "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==",
-            "dev": true
-        },
-        "@types/aria-query": {
-            "version": "5.0.4",
-            "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
-            "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
-            "dev": true
-        },
-        "@types/babel__core": {
-            "version": "7.20.1",
-            "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz",
-            "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==",
-            "dev": true,
-            "requires": {
-                "@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.4",
-            "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz",
-            "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.0.0"
-            }
-        },
-        "@types/babel__template": {
-            "version": "7.4.1",
-            "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz",
-            "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==",
-            "dev": true,
-            "requires": {
-                "@babel/parser": "^7.1.0",
-                "@babel/types": "^7.0.0"
-            }
-        },
-        "@types/babel__traverse": {
-            "version": "7.20.1",
-            "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz",
-            "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==",
-            "dev": true,
-            "requires": {
-                "@babel/types": "^7.20.7"
-            }
-        },
-        "@types/body-parser": {
-            "version": "1.19.2",
-            "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
-            "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
-            "dev": true,
-            "requires": {
-                "@types/connect": "*",
-                "@types/node": "*"
-            }
-        },
-        "@types/bonjour": {
-            "version": "3.5.10",
-            "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz",
-            "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*"
-            }
-        },
-        "@types/clean-css": {
-            "version": "4.2.7",
-            "resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-4.2.7.tgz",
-            "integrity": "sha512-lcoZHjUAANLTACLGi+O/0pN+oKQAQ8zAMWJSxiBRNLxqZG/WE8hfXJUs1eYwJOvOnDJrvxU1kR77UiVJ3+9N0Q==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*",
-                "source-map": "^0.6.0"
-            }
-        },
-        "@types/connect": {
-            "version": "3.4.36",
-            "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz",
-            "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*"
-            }
-        },
-        "@types/connect-history-api-fallback": {
-            "version": "1.5.1",
-            "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.1.tgz",
-            "integrity": "sha512-iaQslNbARe8fctL5Lk+DsmgWOM83lM+7FzP0eQUJs1jd3kBE8NWqBTIT2S8SqQOJjxvt2eyIjpOuYeRXq2AdMw==",
-            "dev": true,
-            "requires": {
-                "@types/express-serve-static-core": "*",
-                "@types/node": "*"
-            }
-        },
-        "@types/d3-array": {
-            "version": "3.0.7",
-            "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.7.tgz",
-            "integrity": "sha512-4/Q0FckQ8TBjsB0VdGFemJOG8BLXUB2KKlL0VmZ+eOYeOnTb/wDRQqYWpBmQ6IlvWkXwkYiot+n9Px2aTJ7zGQ=="
-        },
-        "@types/d3-color": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz",
-            "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA=="
-        },
-        "@types/d3-ease": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz",
-            "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA=="
-        },
-        "@types/d3-interpolate": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
-            "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==",
-            "requires": {
-                "@types/d3-color": "*"
-            }
-        },
-        "@types/d3-path": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz",
-            "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg=="
-        },
-        "@types/d3-scale": {
-            "version": "4.0.4",
-            "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.4.tgz",
-            "integrity": "sha512-eq1ZeTj0yr72L8MQk6N6heP603ubnywSDRfNpi5enouR112HzGLS6RIvExCzZTraFF4HdzNpJMwA/zGiMoHUUw==",
-            "requires": {
-                "@types/d3-time": "*"
-            }
-        },
-        "@types/d3-shape": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.2.tgz",
-            "integrity": "sha512-NN4CXr3qeOUNyK5WasVUV8NCSAx/CRVcwcb0BuuS1PiTqwIm6ABi1SyasLZ/vsVCFDArF+W4QiGzSry1eKYQ7w==",
-            "requires": {
-                "@types/d3-path": "*"
-            }
-        },
-        "@types/d3-time": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz",
-            "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg=="
-        },
-        "@types/d3-timer": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz",
-            "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g=="
-        },
-        "@types/eslint": {
-            "version": "8.44.2",
-            "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.2.tgz",
-            "integrity": "sha512-sdPRb9K6iL5XZOmBubg8yiFp5yS/JdUDQsq5e6h95km91MCYMuvp7mh1fjPEYUhvHepKpZOjnEaMBR4PxjWDzg==",
-            "dev": true,
-            "requires": {
-                "@types/estree": "*",
-                "@types/json-schema": "*"
-            }
-        },
-        "@types/eslint-scope": {
-            "version": "3.7.4",
-            "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
-            "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
-            "dev": true,
-            "requires": {
-                "@types/eslint": "*",
-                "@types/estree": "*"
-            }
-        },
-        "@types/estree": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
-            "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
-            "dev": true
-        },
-        "@types/express": {
-            "version": "4.17.17",
-            "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
-            "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
-            "dev": true,
-            "requires": {
-                "@types/body-parser": "*",
-                "@types/express-serve-static-core": "^4.17.33",
-                "@types/qs": "*",
-                "@types/serve-static": "*"
-            },
-            "dependencies": {
-                "@types/express-serve-static-core": {
-                    "version": "4.17.36",
-                    "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.36.tgz",
-                    "integrity": "sha512-zbivROJ0ZqLAtMzgzIUC4oNqDG9iF0lSsAqpOD9kbs5xcIM3dTiyuHvBc7R8MtWBp3AAWGaovJa+wzWPjLYW7Q==",
-                    "dev": true,
-                    "requires": {
-                        "@types/node": "*",
-                        "@types/qs": "*",
-                        "@types/range-parser": "*",
-                        "@types/send": "*"
-                    }
-                }
-            }
-        },
-        "@types/express-serve-static-core": {
-            "version": "4.17.28",
-            "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
-            "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*",
-                "@types/qs": "*",
-                "@types/range-parser": "*"
-            }
-        },
-        "@types/glob": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz",
-            "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==",
-            "dev": true,
-            "requires": {
-                "@types/minimatch": "*",
-                "@types/node": "*"
-            }
-        },
-        "@types/graceful-fs": {
-            "version": "4.1.9",
-            "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
-            "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*"
-            }
-        },
-        "@types/http-errors": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz",
-            "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==",
-            "dev": true
-        },
-        "@types/http-proxy": {
-            "version": "1.17.11",
-            "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.11.tgz",
-            "integrity": "sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*"
-            }
-        },
-        "@types/imagemin": {
-            "version": "8.0.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin/-/imagemin-8.0.1.tgz",
-            "integrity": "sha512-DSpM//dRPzme7doePGkmR1uoquHi0h0ElaA5qFnxHECfFcB8z/jhMI8eqmxWNpHn9ZG18p4PC918sZLhR0cr5A==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*"
-            }
-        },
-        "@types/imagemin-gifsicle": {
-            "version": "7.0.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin-gifsicle/-/imagemin-gifsicle-7.0.1.tgz",
-            "integrity": "sha512-kUz6sUh0P95JOS0RGEaaemWUrASuw+dLsWIveK2UZJx74id/B9epgblMkCk/r5MjUWbZ83wFvacG5Rb/f97gyA==",
-            "dev": true,
-            "requires": {
-                "@types/imagemin": "*"
-            }
-        },
-        "@types/imagemin-mozjpeg": {
-            "version": "8.0.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin-mozjpeg/-/imagemin-mozjpeg-8.0.1.tgz",
-            "integrity": "sha512-kMQWEoKxxhlnH4POI3qfW9DjXlQfi80ux3l2b3j5R3eudSCoUIzKQLkfMjNJ6eMYnMWBcB+rfQOWqIzdIwFGKw==",
-            "dev": true,
-            "requires": {
-                "@types/imagemin": "*"
-            }
-        },
-        "@types/imagemin-optipng": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin-optipng/-/imagemin-optipng-5.2.1.tgz",
-            "integrity": "sha512-XCM/3q+HUL7v4zOqMI+dJ5dTxT+MUukY9KU49DSnYb/4yWtSMHJyADP+WHSMVzTR63J2ZvfUOzSilzBNEQW78g==",
-            "dev": true,
-            "requires": {
-                "@types/imagemin": "*"
-            }
-        },
-        "@types/imagemin-svgo": {
-            "version": "8.0.1",
-            "resolved": "https://registry.npmjs.org/@types/imagemin-svgo/-/imagemin-svgo-8.0.1.tgz",
-            "integrity": "sha512-YafkdrVAcr38U0Ln1C+L1n4SIZqC47VBHTyxCq7gTUSd1R9MdIvMcrljWlgU1M9O68WZDeQWUrKipKYfEOCOvQ==",
-            "dev": true,
-            "requires": {
-                "@types/imagemin": "*",
-                "@types/svgo": "^1"
-            }
-        },
-        "@types/istanbul-lib-coverage": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
-            "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
-            "dev": true
-        },
-        "@types/istanbul-lib-report": {
-            "version": "3.0.3",
-            "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
-            "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
-            "dev": true,
-            "requires": {
-                "@types/istanbul-lib-coverage": "*"
-            }
-        },
-        "@types/istanbul-reports": {
-            "version": "3.0.4",
-            "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
-            "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
-            "dev": true,
-            "requires": {
-                "@types/istanbul-lib-report": "*"
-            }
-        },
-        "@types/jsdom": {
-            "version": "20.0.1",
-            "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz",
-            "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*",
-                "@types/tough-cookie": "*",
-                "parse5": "^7.0.0"
-            }
-        },
-        "@types/json-schema": {
-            "version": "7.0.12",
-            "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz",
-            "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==",
-            "dev": true
-        },
-        "@types/json5": {
-            "version": "0.0.29",
-            "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
-            "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
-            "dev": true
-        },
-        "@types/mime": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
-            "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==",
-            "dev": true
-        },
-        "@types/minimatch": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
-            "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==",
-            "dev": true
-        },
-        "@types/node": {
-            "version": "20.5.9",
-            "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz",
-            "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==",
-            "dev": true
-        },
-        "@types/parse-json": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
-            "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
-            "dev": true
-        },
-        "@types/prop-types": {
-            "version": "15.7.5",
-            "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
-            "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
-        },
-        "@types/qs": {
-            "version": "6.9.8",
-            "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz",
-            "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==",
-            "dev": true
-        },
-        "@types/range-parser": {
-            "version": "1.2.4",
-            "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
-            "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
-            "dev": true
-        },
-        "@types/react": {
-            "version": "18.2.21",
-            "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz",
-            "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==",
-            "requires": {
-                "@types/prop-types": "*",
-                "@types/scheduler": "*",
-                "csstype": "^3.0.2"
-            }
-        },
-        "@types/react-dom": {
-            "version": "18.2.19",
-            "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.19.tgz",
-            "integrity": "sha512-aZvQL6uUbIJpjZk4U8JZGbau9KDeAwMfmhyWorxgBkqDIEf6ROjRozcmPIicqsUwPUjbkDfHKgGee1Lq65APcA==",
-            "dev": true,
-            "requires": {
-                "@types/react": "*"
-            }
-        },
-        "@types/react-transition-group": {
-            "version": "4.4.6",
-            "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz",
-            "integrity": "sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==",
-            "requires": {
-                "@types/react": "*"
-            }
-        },
-        "@types/retry": {
-            "version": "0.12.0",
-            "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
-            "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
-            "dev": true
-        },
-        "@types/scheduler": {
-            "version": "0.16.3",
-            "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
-            "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
-        },
-        "@types/send": {
-            "version": "0.17.1",
-            "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
-            "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==",
-            "dev": true,
-            "requires": {
-                "@types/mime": "^1",
-                "@types/node": "*"
-            },
-            "dependencies": {
-                "@types/mime": {
-                    "version": "1.3.2",
-                    "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
-                    "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
-                    "dev": true
-                }
-            }
-        },
-        "@types/serve-index": {
-            "version": "1.9.1",
-            "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
-            "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==",
-            "dev": true,
-            "requires": {
-                "@types/express": "*"
-            }
-        },
-        "@types/serve-static": {
-            "version": "1.15.2",
-            "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz",
-            "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==",
-            "dev": true,
-            "requires": {
-                "@types/http-errors": "*",
-                "@types/mime": "*",
-                "@types/node": "*"
-            }
-        },
-        "@types/sockjs": {
-            "version": "0.3.33",
-            "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz",
-            "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*"
-            }
-        },
-        "@types/stack-utils": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
-            "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
-            "dev": true
-        },
-        "@types/svgo": {
-            "version": "1.3.6",
-            "resolved": "https://registry.npmjs.org/@types/svgo/-/svgo-1.3.6.tgz",
-            "integrity": "sha512-AZU7vQcy/4WFEuwnwsNsJnFwupIpbllH1++LXScN6uxT1Z4zPzdrWG97w4/I7eFKFTvfy/bHFStWjdBAg2Vjug==",
-            "dev": true
-        },
-        "@types/tough-cookie": {
-            "version": "4.0.5",
-            "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
-            "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
-            "dev": true
-        },
-        "@types/warning": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
-            "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA=="
-        },
-        "@types/ws": {
-            "version": "8.5.5",
-            "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.5.tgz",
-            "integrity": "sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*"
-            }
-        },
-        "@types/yargs": {
-            "version": "17.0.32",
-            "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
-            "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==",
-            "dev": true,
-            "requires": {
-                "@types/yargs-parser": "*"
-            }
-        },
-        "@types/yargs-parser": {
-            "version": "21.0.3",
-            "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
-            "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
-            "dev": true
-        },
-        "@uiw/codemirror-extensions-basic-setup": {
-            "version": "4.21.13",
-            "resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.21.13.tgz",
-            "integrity": "sha512-5ObHaBqPV00xBVleDFehzPfOQvek5dPM7YLdPHJUE9bumeSflIWJb55n0Zg/w1rsuU0Lt/Q6WJUh4X6VGR1FVw==",
-            "requires": {
-                "@codemirror/autocomplete": "^6.0.0",
-                "@codemirror/commands": "^6.0.0",
-                "@codemirror/language": "^6.0.0",
-                "@codemirror/lint": "^6.0.0",
-                "@codemirror/search": "^6.0.0",
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0"
-            }
-        },
-        "@uiw/codemirror-theme-github": {
-            "version": "4.21.13",
-            "resolved": "https://registry.npmjs.org/@uiw/codemirror-theme-github/-/codemirror-theme-github-4.21.13.tgz",
-            "integrity": "sha512-UblpWrkb+epGSrhf8ztuDO75+GOD8Otf7I/saM3lUzipdeKBOSC7Q7o7De36xbF1HpfOUYbqsajo1X3INf8Y7A==",
-            "requires": {
-                "@uiw/codemirror-themes": "4.21.13"
-            }
-        },
-        "@uiw/codemirror-themes": {
-            "version": "4.21.13",
-            "resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.21.13.tgz",
-            "integrity": "sha512-+IeYow6kmz1LJmXd1rL7ngVxb5lm2wKrjYNfomDvmoUz2gKcca8y7pWGMIFhIsabrNW11SFVSloVkj9ZXw7e1Q==",
-            "requires": {
-                "@codemirror/language": "^6.0.0",
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0"
-            }
-        },
-        "@uiw/react-codemirror": {
-            "version": "4.21.13",
-            "resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.21.13.tgz",
-            "integrity": "sha512-kNX8jLeoDrF2CDa5lsey0MXjBXN3JP00z6AQTTP58mHvlE7Rf03QJSs7bNwwco+3kpwREifFJjnwRe+Y3Gmwtw==",
-            "requires": {
-                "@babel/runtime": "^7.18.6",
-                "@codemirror/commands": "^6.1.0",
-                "@codemirror/state": "^6.1.1",
-                "@codemirror/theme-one-dark": "^6.0.0",
-                "@uiw/codemirror-extensions-basic-setup": "4.21.13",
-                "codemirror": "^6.0.0"
-            }
-        },
-        "@vue/reactivity": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz",
-            "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==",
-            "dev": true,
-            "requires": {
-                "@vue/shared": "3.1.5"
-            }
-        },
-        "@vue/shared": {
-            "version": "3.1.5",
-            "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz",
-            "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==",
-            "dev": true
-        },
-        "@webassemblyjs/ast": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
-            "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
-            "dev": true,
-            "requires": {
-                "@webassemblyjs/helper-numbers": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
-            }
-        },
-        "@webassemblyjs/floating-point-hex-parser": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
-            "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
-            "dev": true
-        },
-        "@webassemblyjs/helper-api-error": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
-            "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
-            "dev": true
-        },
-        "@webassemblyjs/helper-buffer": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
-            "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
-            "dev": true
-        },
-        "@webassemblyjs/helper-numbers": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
-            "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
-            "dev": true,
-            "requires": {
-                "@webassemblyjs/floating-point-hex-parser": "1.11.6",
-                "@webassemblyjs/helper-api-error": "1.11.6",
-                "@xtuc/long": "4.2.2"
-            }
-        },
-        "@webassemblyjs/helper-wasm-bytecode": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
-            "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
-            "dev": true
-        },
-        "@webassemblyjs/helper-wasm-section": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
-            "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
-            "dev": true,
-            "requires": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-buffer": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
-                "@webassemblyjs/wasm-gen": "1.11.6"
-            }
-        },
-        "@webassemblyjs/ieee754": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
-            "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
-            "dev": true,
-            "requires": {
-                "@xtuc/ieee754": "^1.2.0"
-            }
-        },
-        "@webassemblyjs/leb128": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
-            "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
-            "dev": true,
-            "requires": {
-                "@xtuc/long": "4.2.2"
-            }
-        },
-        "@webassemblyjs/utf8": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
-            "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
-            "dev": true
-        },
-        "@webassemblyjs/wasm-edit": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
-            "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
-            "dev": true,
-            "requires": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-buffer": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
-                "@webassemblyjs/helper-wasm-section": "1.11.6",
-                "@webassemblyjs/wasm-gen": "1.11.6",
-                "@webassemblyjs/wasm-opt": "1.11.6",
-                "@webassemblyjs/wasm-parser": "1.11.6",
-                "@webassemblyjs/wast-printer": "1.11.6"
-            }
-        },
-        "@webassemblyjs/wasm-gen": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
-            "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
-            "dev": true,
-            "requires": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
-                "@webassemblyjs/ieee754": "1.11.6",
-                "@webassemblyjs/leb128": "1.11.6",
-                "@webassemblyjs/utf8": "1.11.6"
-            }
-        },
-        "@webassemblyjs/wasm-opt": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
-            "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
-            "dev": true,
-            "requires": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-buffer": "1.11.6",
-                "@webassemblyjs/wasm-gen": "1.11.6",
-                "@webassemblyjs/wasm-parser": "1.11.6"
-            }
-        },
-        "@webassemblyjs/wasm-parser": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
-            "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
-            "dev": true,
-            "requires": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@webassemblyjs/helper-api-error": "1.11.6",
-                "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
-                "@webassemblyjs/ieee754": "1.11.6",
-                "@webassemblyjs/leb128": "1.11.6",
-                "@webassemblyjs/utf8": "1.11.6"
-            }
-        },
-        "@webassemblyjs/wast-printer": {
-            "version": "1.11.6",
-            "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
-            "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
-            "dev": true,
-            "requires": {
-                "@webassemblyjs/ast": "1.11.6",
-                "@xtuc/long": "4.2.2"
-            }
-        },
-        "@webpack-cli/configtest": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
-            "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
-            "dev": true,
-            "requires": {}
-        },
-        "@webpack-cli/info": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
-            "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
-            "dev": true,
-            "requires": {
-                "envinfo": "^7.7.3"
-            }
-        },
-        "@webpack-cli/serve": {
-            "version": "1.7.0",
-            "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
-            "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
-            "dev": true,
-            "requires": {}
-        },
-        "@xtuc/ieee754": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
-            "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
-            "dev": true
-        },
-        "@xtuc/long": {
-            "version": "4.2.2",
-            "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
-            "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
-            "dev": true
-        },
-        "abab": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
-            "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
-            "dev": true
-        },
-        "accepts": {
-            "version": "1.3.8",
-            "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
-            "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
-            "dev": true,
-            "requires": {
-                "mime-types": "~2.1.34",
-                "negotiator": "0.6.3"
-            }
-        },
-        "acorn": {
-            "version": "8.10.0",
-            "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
-            "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
-            "dev": true
-        },
-        "acorn-globals": {
-            "version": "7.0.1",
-            "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz",
-            "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==",
-            "dev": true,
-            "requires": {
-                "acorn": "^8.1.0",
-                "acorn-walk": "^8.0.2"
-            }
-        },
-        "acorn-import-assertions": {
-            "version": "1.9.0",
-            "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
-            "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
-            "dev": true,
-            "requires": {}
-        },
-        "acorn-jsx": {
-            "version": "5.3.2",
-            "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
-            "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
-            "dev": true,
-            "requires": {}
-        },
-        "acorn-walk": {
-            "version": "8.3.2",
-            "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
-            "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
-            "dev": true
-        },
-        "adjust-sourcemap-loader": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz",
-            "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==",
-            "dev": true,
-            "requires": {
-                "loader-utils": "^2.0.0",
-                "regex-parser": "^2.2.11"
-            }
-        },
-        "agent-base": {
-            "version": "6.0.2",
-            "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
-            "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
-            "dev": true,
-            "requires": {
-                "debug": "4"
-            }
-        },
-        "ajv": {
-            "version": "6.12.6",
-            "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-            "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
-            "dev": true,
-            "requires": {
-                "fast-deep-equal": "^3.1.1",
-                "fast-json-stable-stringify": "^2.0.0",
-                "json-schema-traverse": "^0.4.1",
-                "uri-js": "^4.2.2"
-            }
-        },
-        "ajv-formats": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
-            "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
-            "dev": true,
-            "requires": {
-                "ajv": "^8.0.0"
-            },
-            "dependencies": {
-                "ajv": {
-                    "version": "8.12.0",
-                    "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
-                    "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
-                    "dev": true,
-                    "requires": {
-                        "fast-deep-equal": "^3.1.1",
-                        "json-schema-traverse": "^1.0.0",
-                        "require-from-string": "^2.0.2",
-                        "uri-js": "^4.2.2"
-                    }
-                },
-                "json-schema-traverse": {
-                    "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
-                    "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
-                    "dev": true
-                }
-            }
-        },
-        "ajv-keywords": {
-            "version": "3.5.2",
-            "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
-            "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
-            "dev": true,
-            "requires": {}
-        },
-        "alpinejs": {
-            "version": "3.13.0",
-            "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.0.tgz",
-            "integrity": "sha512-7FYR1Yz3evIjlJD1mZ3SYWSw+jlOmQGeQ1QiSufSQ6J84XMQFkzxm6OobiZ928SfqhGdoIp2SsABNsS4rXMMJw==",
-            "dev": true,
-            "requires": {
-                "@vue/reactivity": "~3.1.1"
-            }
-        },
-        "ansi-escapes": {
-            "version": "4.3.2",
-            "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
-            "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
-            "dev": true,
-            "requires": {
-                "type-fest": "^0.21.3"
-            },
-            "dependencies": {
-                "type-fest": {
-                    "version": "0.21.3",
-                    "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
-                    "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
-                    "dev": true
-                }
-            }
-        },
-        "ansi-html-community": {
-            "version": "0.0.8",
-            "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
-            "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
-            "dev": true
-        },
-        "ansi-regex": {
-            "version": "5.0.1",
-            "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-            "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-            "dev": true
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "color-convert": "^1.9.0"
-            }
-        },
-        "any-promise": {
-            "version": "1.3.0",
-            "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
-            "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
-            "dev": true
-        },
-        "anymatch": {
-            "version": "3.1.3",
-            "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
-            "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
-            "dev": true,
-            "requires": {
-                "normalize-path": "^3.0.0",
-                "picomatch": "^2.0.4"
-            }
-        },
-        "apng-js": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/apng-js/-/apng-js-1.1.1.tgz",
-            "integrity": "sha512-UWaloDssWCE8Bj0wipyNxEXPnMadYS0VAjghCLas5nKGqfiBMNdQJhg8Fawq2+jZ50IOM1feKwjiqPAC/bvKgg=="
-        },
-        "arg": {
-            "version": "5.0.2",
-            "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
-            "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
-            "dev": true
-        },
-        "argparse": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-            "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-            "dev": true
-        },
-        "aria-query": {
-            "version": "5.3.0",
-            "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
-            "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
-            "dev": true,
-            "requires": {
-                "dequal": "^2.0.3"
-            }
-        },
-        "array-buffer-byte-length": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
-            "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "is-array-buffer": "^3.0.1"
-            }
-        },
-        "array-flatten": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
-            "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
-            "dev": true
-        },
-        "array-includes": {
-            "version": "3.1.7",
-            "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz",
-            "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1",
-                "is-string": "^1.0.7"
-            }
-        },
-        "array-union": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-            "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-            "dev": true
-        },
-        "array.prototype.findlastindex": {
-            "version": "1.2.3",
-            "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz",
-            "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "es-shim-unscopables": "^1.0.0",
-                "get-intrinsic": "^1.2.1"
-            }
-        },
-        "array.prototype.flat": {
-            "version": "1.3.2",
-            "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
-            "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "es-shim-unscopables": "^1.0.0"
-            }
-        },
-        "array.prototype.flatmap": {
-            "version": "1.3.1",
-            "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
-            "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "es-abstract": "^1.20.4",
-                "es-shim-unscopables": "^1.0.0"
-            }
-        },
-        "array.prototype.tosorted": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz",
-            "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "es-abstract": "^1.20.4",
-                "es-shim-unscopables": "^1.0.0",
-                "get-intrinsic": "^1.1.3"
-            }
-        },
-        "arraybuffer.prototype.slice": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz",
-            "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==",
-            "dev": true,
-            "requires": {
-                "array-buffer-byte-length": "^1.0.0",
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1",
-                "is-array-buffer": "^3.0.2",
-                "is-shared-array-buffer": "^1.0.2"
-            }
-        },
-        "asn1.js": {
-            "version": "5.4.1",
-            "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
-            "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
-            "dev": true,
-            "requires": {
-                "bn.js": "^4.0.0",
-                "inherits": "^2.0.1",
-                "minimalistic-assert": "^1.0.0",
-                "safer-buffer": "^2.1.0"
-            },
-            "dependencies": {
-                "bn.js": {
-                    "version": "4.12.0",
-                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-                    "dev": true
-                }
-            }
-        },
-        "assert": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
-            "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
-            "dev": true,
-            "requires": {
-                "object-assign": "^4.1.1",
-                "util": "0.10.3"
-            },
-            "dependencies": {
-                "inherits": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
-                    "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==",
-                    "dev": true
-                },
-                "util": {
-                    "version": "0.10.3",
-                    "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
-                    "integrity": "sha512-5KiHfsmkqacuKjkRkdV7SsfDJ2EGiPsK92s2MhNSY0craxjTdKTtqKsJaCWp4LW33ZZ0OPUv1WO/TFvNQRiQxQ==",
-                    "dev": true,
-                    "requires": {
-                        "inherits": "2.0.1"
-                    }
-                }
-            }
-        },
-        "asynciterator.prototype": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz",
-            "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==",
-            "dev": true,
-            "requires": {
-                "has-symbols": "^1.0.3"
-            }
-        },
-        "asynckit": {
-            "version": "0.4.0",
-            "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-            "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
-            "dev": true
-        },
-        "autoprefixer": {
-            "version": "10.4.15",
-            "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz",
-            "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.21.10",
-                "caniuse-lite": "^1.0.30001520",
-                "fraction.js": "^4.2.0",
-                "normalize-range": "^0.1.2",
-                "picocolors": "^1.0.0",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "available-typed-arrays": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
-            "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
-            "dev": true,
-            "requires": {
-                "possible-typed-array-names": "^1.0.0"
-            }
-        },
-        "axios": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
-            "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
-            "dev": true,
-            "requires": {
-                "follow-redirects": "^1.15.0",
-                "form-data": "^4.0.0",
-                "proxy-from-env": "^1.1.0"
-            }
-        },
-        "babel-jest": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
-            "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
-            "dev": true,
-            "requires": {
-                "@jest/transform": "^29.7.0",
-                "@types/babel__core": "^7.1.14",
-                "babel-plugin-istanbul": "^6.1.1",
-                "babel-preset-jest": "^29.6.3",
-                "chalk": "^4.0.0",
-                "graceful-fs": "^4.2.9",
-                "slash": "^3.0.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "babel-loader": {
-            "version": "8.3.0",
-            "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.3.0.tgz",
-            "integrity": "sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==",
-            "dev": true,
-            "requires": {
-                "find-cache-dir": "^3.3.1",
-                "loader-utils": "^2.0.0",
-                "make-dir": "^3.1.0",
-                "schema-utils": "^2.6.5"
-            }
-        },
-        "babel-plugin-istanbul": {
-            "version": "6.1.1",
-            "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
-            "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-plugin-utils": "^7.0.0",
-                "@istanbuljs/load-nyc-config": "^1.0.0",
-                "@istanbuljs/schema": "^0.1.2",
-                "istanbul-lib-instrument": "^5.0.4",
-                "test-exclude": "^6.0.0"
-            },
-            "dependencies": {
-                "istanbul-lib-instrument": {
-                    "version": "5.2.1",
-                    "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
-                    "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
-                    "dev": true,
-                    "requires": {
-                        "@babel/core": "^7.12.3",
-                        "@babel/parser": "^7.14.7",
-                        "@istanbuljs/schema": "^0.1.2",
-                        "istanbul-lib-coverage": "^3.2.0",
-                        "semver": "^6.3.0"
-                    }
-                }
-            }
-        },
-        "babel-plugin-jest-hoist": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
-            "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
-            "dev": true,
-            "requires": {
-                "@babel/template": "^7.3.3",
-                "@babel/types": "^7.3.3",
-                "@types/babel__core": "^7.1.14",
-                "@types/babel__traverse": "^7.0.6"
-            }
-        },
-        "babel-plugin-polyfill-corejs2": {
-            "version": "0.4.5",
-            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz",
-            "integrity": "sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg==",
-            "dev": true,
-            "requires": {
-                "@babel/compat-data": "^7.22.6",
-                "@babel/helper-define-polyfill-provider": "^0.4.2",
-                "semver": "^6.3.1"
-            }
-        },
-        "babel-plugin-polyfill-corejs3": {
-            "version": "0.8.3",
-            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz",
-            "integrity": "sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-define-polyfill-provider": "^0.4.2",
-                "core-js-compat": "^3.31.0"
-            }
-        },
-        "babel-plugin-polyfill-regenerator": {
-            "version": "0.5.2",
-            "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz",
-            "integrity": "sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA==",
-            "dev": true,
-            "requires": {
-                "@babel/helper-define-polyfill-provider": "^0.4.2"
-            }
-        },
-        "babel-preset-current-node-syntax": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
-            "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
-            "dev": true,
-            "requires": {
-                "@babel/plugin-syntax-async-generators": "^7.8.4",
-                "@babel/plugin-syntax-bigint": "^7.8.3",
-                "@babel/plugin-syntax-class-properties": "^7.8.3",
-                "@babel/plugin-syntax-import-meta": "^7.8.3",
-                "@babel/plugin-syntax-json-strings": "^7.8.3",
-                "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
-                "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
-                "@babel/plugin-syntax-numeric-separator": "^7.8.3",
-                "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
-                "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
-                "@babel/plugin-syntax-optional-chaining": "^7.8.3",
-                "@babel/plugin-syntax-top-level-await": "^7.8.3"
-            }
-        },
-        "babel-preset-jest": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
-            "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
-            "dev": true,
-            "requires": {
-                "babel-plugin-jest-hoist": "^29.6.3",
-                "babel-preset-current-node-syntax": "^1.0.0"
-            }
-        },
-        "balanced-match": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
-            "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
-            "dev": true
-        },
-        "base64-js": {
-            "version": "1.5.1",
-            "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
-            "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
-            "dev": true
-        },
-        "batch": {
-            "version": "0.6.1",
-            "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
-            "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
-            "dev": true
-        },
-        "big.js": {
-            "version": "5.2.2",
-            "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-            "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
-            "dev": true
-        },
-        "binary-extensions": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
-            "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-            "dev": true
-        },
-        "bn.js": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
-            "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
-            "dev": true
-        },
-        "body-parser": {
-            "version": "1.20.1",
-            "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
-            "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
-            "dev": true,
-            "requires": {
-                "bytes": "3.1.2",
-                "content-type": "~1.0.4",
-                "debug": "2.6.9",
-                "depd": "2.0.0",
-                "destroy": "1.2.0",
-                "http-errors": "2.0.0",
-                "iconv-lite": "0.4.24",
-                "on-finished": "2.4.1",
-                "qs": "6.11.0",
-                "raw-body": "2.5.1",
-                "type-is": "~1.6.18",
-                "unpipe": "1.0.0"
-            },
-            "dependencies": {
-                "bytes": {
-                    "version": "3.1.2",
-                    "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
-                    "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
-                    "dev": true
-                },
-                "debug": {
-                    "version": "2.6.9",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-                    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "2.0.0"
-                    }
-                },
-                "ms": {
-                    "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                    "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-                    "dev": true
-                },
-                "qs": {
-                    "version": "6.11.0",
-                    "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
-                    "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
-                    "dev": true,
-                    "requires": {
-                        "side-channel": "^1.0.4"
-                    }
-                }
-            }
-        },
-        "bonjour-service": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz",
-            "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==",
-            "dev": true,
-            "requires": {
-                "array-flatten": "^2.1.2",
-                "dns-equal": "^1.0.0",
-                "fast-deep-equal": "^3.1.3",
-                "multicast-dns": "^7.2.5"
-            }
-        },
-        "boolbase": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-            "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
-            "dev": true
-        },
-        "bootstrap": {
-            "version": "5.3.1",
-            "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.1.tgz",
-            "integrity": "sha512-jzwza3Yagduci2x0rr9MeFSORjcHpt0lRZukZPZQJT1Dth5qzV7XcgGqYzi39KGAVYR8QEDVoO0ubFKOxzMG+g==",
-            "dev": true,
-            "requires": {}
-        },
-        "brace-expansion": {
-            "version": "1.1.11",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-            "dev": true,
-            "requires": {
-                "balanced-match": "^1.0.0",
-                "concat-map": "0.0.1"
-            }
-        },
-        "braces": {
-            "version": "3.0.2",
-            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-            "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-            "dev": true,
-            "requires": {
-                "fill-range": "^7.0.1"
-            }
-        },
-        "brorand": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
-            "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
-            "dev": true
-        },
-        "browserify-aes": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
-            "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
-            "dev": true,
-            "requires": {
-                "buffer-xor": "^1.0.3",
-                "cipher-base": "^1.0.0",
-                "create-hash": "^1.1.0",
-                "evp_bytestokey": "^1.0.3",
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.0.1"
-            }
-        },
-        "browserify-cipher": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
-            "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
-            "dev": true,
-            "requires": {
-                "browserify-aes": "^1.0.4",
-                "browserify-des": "^1.0.0",
-                "evp_bytestokey": "^1.0.0"
-            }
-        },
-        "browserify-des": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
-            "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
-            "dev": true,
-            "requires": {
-                "cipher-base": "^1.0.1",
-                "des.js": "^1.0.0",
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.1.2"
-            }
-        },
-        "browserify-rsa": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
-            "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
-            "dev": true,
-            "requires": {
-                "bn.js": "^5.0.0",
-                "randombytes": "^2.0.1"
-            }
-        },
-        "browserify-sign": {
-            "version": "4.2.1",
-            "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
-            "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
-            "dev": true,
-            "requires": {
-                "bn.js": "^5.1.1",
-                "browserify-rsa": "^4.0.1",
-                "create-hash": "^1.2.0",
-                "create-hmac": "^1.1.7",
-                "elliptic": "^6.5.3",
-                "inherits": "^2.0.4",
-                "parse-asn1": "^5.1.5",
-                "readable-stream": "^3.6.0",
-                "safe-buffer": "^5.2.0"
-            },
-            "dependencies": {
-                "readable-stream": {
-                    "version": "3.6.2",
-                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-                    "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
-                    "dev": true,
-                    "requires": {
-                        "inherits": "^2.0.3",
-                        "string_decoder": "^1.1.1",
-                        "util-deprecate": "^1.0.1"
-                    }
-                }
-            }
-        },
-        "browserify-zlib": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
-            "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
-            "dev": true,
-            "requires": {
-                "pako": "~1.0.5"
-            }
-        },
-        "browserslist": {
-            "version": "4.23.0",
-            "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
-            "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
-            "dev": true,
-            "requires": {
-                "caniuse-lite": "^1.0.30001587",
-                "electron-to-chromium": "^1.4.668",
-                "node-releases": "^2.0.14",
-                "update-browserslist-db": "^1.0.13"
-            }
-        },
-        "bser": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
-            "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
-            "dev": true,
-            "requires": {
-                "node-int64": "^0.4.0"
-            }
-        },
-        "buffer": {
-            "version": "4.9.2",
-            "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
-            "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
-            "dev": true,
-            "requires": {
-                "base64-js": "^1.0.2",
-                "ieee754": "^1.1.4",
-                "isarray": "^1.0.0"
-            }
-        },
-        "buffer-from": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
-            "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
-            "dev": true
-        },
-        "buffer-xor": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
-            "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
-            "dev": true
-        },
-        "builtin-status-codes": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
-            "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==",
-            "dev": true
-        },
-        "bytes": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
-            "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==",
-            "dev": true
-        },
-        "call-bind": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
-            "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
-            "requires": {
-                "es-define-property": "^1.0.0",
-                "es-errors": "^1.3.0",
-                "function-bind": "^1.1.2",
-                "get-intrinsic": "^1.2.4",
-                "set-function-length": "^1.2.1"
-            }
-        },
-        "callsites": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-            "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-            "dev": true
-        },
-        "camel-case": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
-            "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
-            "dev": true,
-            "requires": {
-                "pascal-case": "^3.1.2",
-                "tslib": "^2.0.3"
-            }
-        },
-        "camelcase": {
-            "version": "5.3.1",
-            "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-            "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-            "dev": true
-        },
-        "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==",
-            "dev": true
-        },
-        "caniuse-api": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
-            "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.0.0",
-                "caniuse-lite": "^1.0.0",
-                "lodash.memoize": "^4.1.2",
-                "lodash.uniq": "^4.5.0"
-            }
-        },
-        "caniuse-lite": {
-            "version": "1.0.30001589",
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001589.tgz",
-            "integrity": "sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==",
-            "dev": true
-        },
-        "chalk": {
-            "version": "2.4.2",
-            "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-            "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-            "dev": true,
-            "requires": {
-                "ansi-styles": "^3.2.1",
-                "escape-string-regexp": "^1.0.5",
-                "supports-color": "^5.3.0"
-            }
-        },
-        "char-regex": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
-            "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
-            "dev": true
-        },
-        "charenc": {
-            "version": "0.0.2",
-            "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
-            "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
-            "dev": true
-        },
-        "chokidar": {
-            "version": "3.5.3",
-            "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
-            "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
-            "dev": true,
-            "requires": {
-                "anymatch": "~3.1.2",
-                "braces": "~3.0.2",
-                "fsevents": "~2.3.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"
-            },
-            "dependencies": {
-                "glob-parent": {
-                    "version": "5.1.2",
-                    "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-                    "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-                    "dev": true,
-                    "requires": {
-                        "is-glob": "^4.0.1"
-                    }
-                }
-            }
-        },
-        "chrome-trace-event": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
-            "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
-            "dev": true
-        },
-        "ci-info": {
-            "version": "3.9.0",
-            "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
-            "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
-            "dev": true
-        },
-        "cipher-base": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
-            "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
-            "dev": true,
-            "requires": {
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.0.1"
-            }
-        },
-        "cjs-module-lexer": {
-            "version": "1.2.3",
-            "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz",
-            "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==",
-            "dev": true
-        },
-        "classnames": {
-            "version": "2.3.2",
-            "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
-            "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
-        },
-        "clean-css": {
-            "version": "5.3.2",
-            "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz",
-            "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==",
-            "dev": true,
-            "requires": {
-                "source-map": "~0.6.0"
-            }
-        },
-        "cli-table3": {
-            "version": "0.6.3",
-            "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz",
-            "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==",
-            "dev": true,
-            "requires": {
-                "@colors/colors": "1.5.0",
-                "string-width": "^4.2.0"
-            }
-        },
-        "cliui": {
-            "version": "8.0.1",
-            "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
-            "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
-            "dev": true,
-            "requires": {
-                "string-width": "^4.2.0",
-                "strip-ansi": "^6.0.1",
-                "wrap-ansi": "^7.0.0"
-            }
-        },
-        "clone-deep": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
-            "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
-            "dev": true,
-            "requires": {
-                "is-plain-object": "^2.0.4",
-                "kind-of": "^6.0.2",
-                "shallow-clone": "^3.0.0"
-            }
-        },
-        "co": {
-            "version": "4.6.0",
-            "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
-            "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
-            "dev": true
-        },
-        "codemirror": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
-            "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
-            "requires": {
-                "@codemirror/autocomplete": "^6.0.0",
-                "@codemirror/commands": "^6.0.0",
-                "@codemirror/language": "^6.0.0",
-                "@codemirror/lint": "^6.0.0",
-                "@codemirror/search": "^6.0.0",
-                "@codemirror/state": "^6.0.0",
-                "@codemirror/view": "^6.0.0"
-            }
-        },
-        "collect-v8-coverage": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
-            "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==",
-            "dev": true
-        },
-        "collect.js": {
-            "version": "4.36.1",
-            "resolved": "https://registry.npmjs.org/collect.js/-/collect.js-4.36.1.tgz",
-            "integrity": "sha512-jd97xWPKgHn6uvK31V6zcyPd40lUJd7gpYxbN2VOVxGWO4tyvS9Li4EpsFjXepGTo2tYcOTC4a8YsbQXMJ4XUw==",
-            "dev": true
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "color-name": "1.1.3"
-            }
-        },
-        "color-name": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-            "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
-            "dev": true
-        },
-        "colord": {
-            "version": "2.9.3",
-            "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
-            "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
-            "dev": true
-        },
-        "colorette": {
-            "version": "2.0.20",
-            "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
-            "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
-            "dev": true
-        },
-        "combined-stream": {
-            "version": "1.0.8",
-            "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
-            "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-            "dev": true,
-            "requires": {
-                "delayed-stream": "~1.0.0"
-            }
-        },
-        "commander": {
-            "version": "7.2.0",
-            "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
-            "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
-            "dev": true
-        },
-        "commondir": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-            "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
-            "dev": true
-        },
-        "compressible": {
-            "version": "2.0.18",
-            "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
-            "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
-            "dev": true,
-            "requires": {
-                "mime-db": ">= 1.43.0 < 2"
-            }
-        },
-        "compression": {
-            "version": "1.7.4",
-            "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
-            "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
-            "dev": true,
-            "requires": {
-                "accepts": "~1.3.5",
-                "bytes": "3.0.0",
-                "compressible": "~2.0.16",
-                "debug": "2.6.9",
-                "on-headers": "~1.0.2",
-                "safe-buffer": "5.1.2",
-                "vary": "~1.1.2"
-            },
-            "dependencies": {
-                "debug": {
-                    "version": "2.6.9",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-                    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "2.0.0"
-                    }
-                },
-                "ms": {
-                    "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                    "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-                    "dev": true
-                },
-                "safe-buffer": {
-                    "version": "5.1.2",
-                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-                    "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-                    "dev": true
-                }
-            }
-        },
-        "concat": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/concat/-/concat-1.0.3.tgz",
-            "integrity": "sha512-f/ZaH1aLe64qHgTILdldbvyfGiGF4uzeo9IuXUloIOLQzFmIPloy9QbZadNsuVv0j5qbKQvQb/H/UYf2UsKTpw==",
-            "dev": true,
-            "requires": {
-                "commander": "^2.9.0"
-            },
-            "dependencies": {
-                "commander": {
-                    "version": "2.20.3",
-                    "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-                    "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-                    "dev": true
-                }
-            }
-        },
-        "concat-map": {
-            "version": "0.0.1",
-            "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-            "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
-            "dev": true
-        },
-        "connect-history-api-fallback": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
-            "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==",
-            "dev": true
-        },
-        "consola": {
-            "version": "2.15.3",
-            "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz",
-            "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==",
-            "dev": true
-        },
-        "console-browserify": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
-            "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
-            "dev": true
-        },
-        "constants-browserify": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
-            "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==",
-            "dev": true
-        },
-        "content-disposition": {
-            "version": "0.5.4",
-            "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
-            "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
-            "dev": true,
-            "requires": {
-                "safe-buffer": "5.2.1"
-            }
-        },
-        "content-type": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
-            "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
-            "dev": true
-        },
-        "convert-source-map": {
-            "version": "1.9.0",
-            "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
-            "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
-            "dev": true
-        },
-        "cookie": {
-            "version": "0.5.0",
-            "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
-            "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
-            "dev": true
-        },
-        "cookie-signature": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
-            "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
-            "dev": true
-        },
-        "core-js-compat": {
-            "version": "3.32.1",
-            "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.1.tgz",
-            "integrity": "sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.21.10"
-            }
-        },
-        "core-util-is": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
-            "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
-            "dev": true
-        },
-        "cosmiconfig": {
-            "version": "7.1.0",
-            "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
-            "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
-            "dev": true,
-            "requires": {
-                "@types/parse-json": "^4.0.0",
-                "import-fresh": "^3.2.1",
-                "parse-json": "^5.0.0",
-                "path-type": "^4.0.0",
-                "yaml": "^1.10.0"
-            }
-        },
-        "crc-32": {
-            "version": "1.2.2",
-            "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
-            "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="
-        },
-        "create-ecdh": {
-            "version": "4.0.4",
-            "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
-            "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
-            "dev": true,
-            "requires": {
-                "bn.js": "^4.1.0",
-                "elliptic": "^6.5.3"
-            },
-            "dependencies": {
-                "bn.js": {
-                    "version": "4.12.0",
-                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-                    "dev": true
-                }
-            }
-        },
-        "create-hash": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
-            "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
-            "dev": true,
-            "requires": {
-                "cipher-base": "^1.0.1",
-                "inherits": "^2.0.1",
-                "md5.js": "^1.3.4",
-                "ripemd160": "^2.0.1",
-                "sha.js": "^2.4.0"
-            }
-        },
-        "create-hmac": {
-            "version": "1.1.7",
-            "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
-            "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
-            "dev": true,
-            "requires": {
-                "cipher-base": "^1.0.3",
-                "create-hash": "^1.1.0",
-                "inherits": "^2.0.1",
-                "ripemd160": "^2.0.0",
-                "safe-buffer": "^5.0.1",
-                "sha.js": "^2.4.8"
-            }
-        },
-        "create-jest": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
-            "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
-            "dev": true,
-            "requires": {
-                "@jest/types": "^29.6.3",
-                "chalk": "^4.0.0",
-                "exit": "^0.1.2",
-                "graceful-fs": "^4.2.9",
-                "jest-config": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "prompts": "^2.0.1"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "crelt": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
-            "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="
-        },
-        "cross-spawn": {
-            "version": "7.0.3",
-            "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
-            "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
-            "dev": true,
-            "requires": {
-                "path-key": "^3.1.0",
-                "shebang-command": "^2.0.0",
-                "which": "^2.0.1"
-            }
-        },
-        "crypt": {
-            "version": "0.0.2",
-            "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
-            "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
-            "dev": true
-        },
-        "crypto-browserify": {
-            "version": "3.12.0",
-            "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
-            "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
-            "dev": true,
-            "requires": {
-                "browserify-cipher": "^1.0.0",
-                "browserify-sign": "^4.0.0",
-                "create-ecdh": "^4.0.0",
-                "create-hash": "^1.1.0",
-                "create-hmac": "^1.1.0",
-                "diffie-hellman": "^5.0.0",
-                "inherits": "^2.0.1",
-                "pbkdf2": "^3.0.3",
-                "public-encrypt": "^4.0.0",
-                "randombytes": "^2.0.0",
-                "randomfill": "^1.0.3"
-            }
-        },
-        "css-declaration-sorter": {
-            "version": "6.4.1",
-            "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz",
-            "integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==",
-            "dev": true,
-            "requires": {}
-        },
-        "css-loader": {
-            "version": "5.2.7",
-            "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz",
-            "integrity": "sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==",
-            "dev": true,
-            "requires": {
-                "icss-utils": "^5.1.0",
-                "loader-utils": "^2.0.0",
-                "postcss": "^8.2.15",
-                "postcss-modules-extract-imports": "^3.0.0",
-                "postcss-modules-local-by-default": "^4.0.0",
-                "postcss-modules-scope": "^3.0.0",
-                "postcss-modules-values": "^4.0.0",
-                "postcss-value-parser": "^4.1.0",
-                "schema-utils": "^3.0.0",
-                "semver": "^7.3.5"
-            },
-            "dependencies": {
-                "lru-cache": {
-                    "version": "6.0.0",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-                    "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-                    "dev": true,
-                    "requires": {
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "schema-utils": {
-                    "version": "3.3.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-                    "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.8",
-                        "ajv": "^6.12.5",
-                        "ajv-keywords": "^3.5.2"
-                    }
-                },
-                "semver": {
-                    "version": "7.5.4",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-                    "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
-                    "dev": true,
-                    "requires": {
-                        "lru-cache": "^6.0.0"
-                    }
-                },
-                "yallist": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-                    "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-                    "dev": true
-                }
-            }
-        },
-        "css-select": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
-            "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
-            "dev": true,
-            "requires": {
-                "boolbase": "^1.0.0",
-                "css-what": "^6.0.1",
-                "domhandler": "^4.3.1",
-                "domutils": "^2.8.0",
-                "nth-check": "^2.0.1"
-            },
-            "dependencies": {
-                "domhandler": {
-                    "version": "4.3.1",
-                    "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
-                    "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
-                    "dev": true,
-                    "requires": {
-                        "domelementtype": "^2.2.0"
-                    }
-                }
-            }
-        },
-        "css-tree": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
-            "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
-            "dev": true,
-            "requires": {
-                "mdn-data": "2.0.14",
-                "source-map": "^0.6.1"
-            }
-        },
-        "css-unit-converter": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
-            "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
-        },
-        "css-what": {
-            "version": "6.1.0",
-            "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
-            "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
-            "dev": true
-        },
-        "css.escape": {
-            "version": "1.5.1",
-            "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
-            "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==",
-            "dev": true
-        },
-        "cssesc": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
-            "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
-            "dev": true
-        },
-        "cssnano": {
-            "version": "5.1.15",
-            "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz",
-            "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==",
-            "dev": true,
-            "requires": {
-                "cssnano-preset-default": "^5.2.14",
-                "lilconfig": "^2.0.3",
-                "yaml": "^1.10.2"
-            }
-        },
-        "cssnano-preset-default": {
-            "version": "5.2.14",
-            "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz",
-            "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==",
-            "dev": true,
-            "requires": {
-                "css-declaration-sorter": "^6.3.1",
-                "cssnano-utils": "^3.1.0",
-                "postcss-calc": "^8.2.3",
-                "postcss-colormin": "^5.3.1",
-                "postcss-convert-values": "^5.1.3",
-                "postcss-discard-comments": "^5.1.2",
-                "postcss-discard-duplicates": "^5.1.0",
-                "postcss-discard-empty": "^5.1.1",
-                "postcss-discard-overridden": "^5.1.0",
-                "postcss-merge-longhand": "^5.1.7",
-                "postcss-merge-rules": "^5.1.4",
-                "postcss-minify-font-values": "^5.1.0",
-                "postcss-minify-gradients": "^5.1.1",
-                "postcss-minify-params": "^5.1.4",
-                "postcss-minify-selectors": "^5.2.1",
-                "postcss-normalize-charset": "^5.1.0",
-                "postcss-normalize-display-values": "^5.1.0",
-                "postcss-normalize-positions": "^5.1.1",
-                "postcss-normalize-repeat-style": "^5.1.1",
-                "postcss-normalize-string": "^5.1.0",
-                "postcss-normalize-timing-functions": "^5.1.0",
-                "postcss-normalize-unicode": "^5.1.1",
-                "postcss-normalize-url": "^5.1.0",
-                "postcss-normalize-whitespace": "^5.1.1",
-                "postcss-ordered-values": "^5.1.3",
-                "postcss-reduce-initial": "^5.1.2",
-                "postcss-reduce-transforms": "^5.1.0",
-                "postcss-svgo": "^5.1.0",
-                "postcss-unique-selectors": "^5.1.1"
-            }
-        },
-        "cssnano-utils": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-3.1.0.tgz",
-            "integrity": "sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==",
-            "dev": true,
-            "requires": {}
-        },
-        "csso": {
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
-            "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
-            "dev": true,
-            "requires": {
-                "css-tree": "^1.1.2"
-            }
-        },
-        "cssom": {
-            "version": "0.5.0",
-            "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz",
-            "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==",
-            "dev": true
-        },
-        "cssstyle": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
-            "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
-            "dev": true,
-            "requires": {
-                "cssom": "~0.3.6"
-            },
-            "dependencies": {
-                "cssom": {
-                    "version": "0.3.8",
-                    "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
-                    "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
-                    "dev": true
-                }
-            }
-        },
-        "csstype": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
-            "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
-        },
-        "d3-array": {
-            "version": "3.2.4",
-            "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
-            "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
-            "requires": {
-                "internmap": "1 - 2"
-            }
-        },
-        "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=="
-        },
-        "d3-dispatch": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
-            "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg=="
-        },
-        "d3-drag": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
-            "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
-            "requires": {
-                "d3-dispatch": "1 - 3",
-                "d3-selection": "3"
-            }
-        },
-        "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=="
-        },
-        "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=="
-        },
-        "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==",
-            "requires": {
-                "d3-color": "1 - 3"
-            }
-        },
-        "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=="
-        },
-        "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==",
-            "requires": {
-                "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-selection": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
-            "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ=="
-        },
-        "d3-shape": {
-            "version": "3.2.0",
-            "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
-            "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
-            "requires": {
-                "d3-path": "^3.1.0"
-            }
-        },
-        "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==",
-            "requires": {
-                "d3-array": "2 - 3"
-            }
-        },
-        "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==",
-            "requires": {
-                "d3-time": "1 - 3"
-            }
-        },
-        "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=="
-        },
-        "data-urls": {
-            "version": "3.0.2",
-            "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz",
-            "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==",
-            "dev": true,
-            "requires": {
-                "abab": "^2.0.6",
-                "whatwg-mimetype": "^3.0.0",
-                "whatwg-url": "^11.0.0"
-            }
-        },
-        "debug": {
-            "version": "4.3.4",
-            "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
-            "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
-            "dev": true,
-            "requires": {
-                "ms": "2.1.2"
-            }
-        },
-        "decimal.js": {
-            "version": "10.4.3",
-            "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
-            "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
-            "dev": true
-        },
-        "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=="
-        },
-        "dedent": {
-            "version": "1.5.1",
-            "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz",
-            "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==",
-            "dev": true,
-            "requires": {}
-        },
-        "deep-equal": {
-            "version": "2.2.3",
-            "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
-            "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
-            "dev": true,
-            "requires": {
-                "array-buffer-byte-length": "^1.0.0",
-                "call-bind": "^1.0.5",
-                "es-get-iterator": "^1.1.3",
-                "get-intrinsic": "^1.2.2",
-                "is-arguments": "^1.1.1",
-                "is-array-buffer": "^3.0.2",
-                "is-date-object": "^1.0.5",
-                "is-regex": "^1.1.4",
-                "is-shared-array-buffer": "^1.0.2",
-                "isarray": "^2.0.5",
-                "object-is": "^1.1.5",
-                "object-keys": "^1.1.1",
-                "object.assign": "^4.1.4",
-                "regexp.prototype.flags": "^1.5.1",
-                "side-channel": "^1.0.4",
-                "which-boxed-primitive": "^1.0.2",
-                "which-collection": "^1.0.1",
-                "which-typed-array": "^1.1.13"
-            },
-            "dependencies": {
-                "isarray": {
-                    "version": "2.0.5",
-                    "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-                    "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-                    "dev": true
-                }
-            }
-        },
-        "deep-is": {
-            "version": "0.1.4",
-            "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
-            "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-            "dev": true
-        },
-        "deepmerge": {
-            "version": "2.2.1",
-            "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
-            "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA=="
-        },
-        "default-gateway": {
-            "version": "6.0.3",
-            "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
-            "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==",
-            "dev": true,
-            "requires": {
-                "execa": "^5.0.0"
-            }
-        },
-        "define-data-property": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
-            "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
-            "requires": {
-                "es-define-property": "^1.0.0",
-                "es-errors": "^1.3.0",
-                "gopd": "^1.0.1"
-            }
-        },
-        "define-lazy-prop": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
-            "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
-            "dev": true
-        },
-        "define-properties": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
-            "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
-            "dev": true,
-            "requires": {
-                "define-data-property": "^1.0.1",
-                "has-property-descriptors": "^1.0.0",
-                "object-keys": "^1.1.1"
-            }
-        },
-        "delayed-stream": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-            "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
-            "dev": true
-        },
-        "depd": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-            "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
-            "dev": true
-        },
-        "dequal": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
-            "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="
-        },
-        "des.js": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
-            "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
-            "dev": true,
-            "requires": {
-                "inherits": "^2.0.1",
-                "minimalistic-assert": "^1.0.0"
-            }
-        },
-        "destroy": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
-            "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
-            "dev": true
-        },
-        "detect-newline": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
-            "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
-            "dev": true
-        },
-        "detect-node": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
-            "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
-            "dev": true
-        },
-        "didyoumean": {
-            "version": "1.2.2",
-            "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
-            "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
-            "dev": true
-        },
-        "diff-sequences": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
-            "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
-            "dev": true
-        },
-        "diffie-hellman": {
-            "version": "5.0.3",
-            "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
-            "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
-            "dev": true,
-            "requires": {
-                "bn.js": "^4.1.0",
-                "miller-rabin": "^4.0.0",
-                "randombytes": "^2.0.0"
-            },
-            "dependencies": {
-                "bn.js": {
-                    "version": "4.12.0",
-                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-                    "dev": true
-                }
-            }
-        },
-        "dir-glob": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
-            "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
-            "dev": true,
-            "requires": {
-                "path-type": "^4.0.0"
-            }
-        },
-        "dlv": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
-            "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
-            "dev": true
-        },
-        "dns-equal": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
-            "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==",
-            "dev": true
-        },
-        "dns-packet": {
-            "version": "5.6.1",
-            "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz",
-            "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==",
-            "dev": true,
-            "requires": {
-                "@leichtgewicht/ip-codec": "^2.0.1"
-            }
-        },
-        "doctrine": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-            "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
-            "dev": true,
-            "requires": {
-                "esutils": "^2.0.2"
-            }
-        },
-        "dom-accessibility-api": {
-            "version": "0.6.3",
-            "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz",
-            "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==",
-            "dev": true
-        },
-        "dom-helpers": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
-            "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
-            "requires": {
-                "@babel/runtime": "^7.8.7",
-                "csstype": "^3.0.2"
-            }
-        },
-        "dom-serializer": {
-            "version": "1.4.1",
-            "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
-            "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
-            "dev": true,
-            "requires": {
-                "domelementtype": "^2.0.1",
-                "domhandler": "^4.2.0",
-                "entities": "^2.0.0"
-            },
-            "dependencies": {
-                "domhandler": {
-                    "version": "4.3.1",
-                    "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
-                    "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
-                    "dev": true,
-                    "requires": {
-                        "domelementtype": "^2.2.0"
-                    }
-                }
-            }
-        },
-        "domain-browser": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
-            "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
-            "dev": true
-        },
-        "domelementtype": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
-            "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
-            "dev": true
-        },
-        "domexception": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
-            "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==",
-            "dev": true,
-            "requires": {
-                "webidl-conversions": "^7.0.0"
-            }
-        },
-        "domhandler": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
-            "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
-            "dev": true,
-            "requires": {
-                "domelementtype": "^2.0.1"
-            }
-        },
-        "domutils": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
-            "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
-            "dev": true,
-            "requires": {
-                "dom-serializer": "^1.0.1",
-                "domelementtype": "^2.2.0",
-                "domhandler": "^4.2.0"
-            },
-            "dependencies": {
-                "domhandler": {
-                    "version": "4.3.1",
-                    "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
-                    "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
-                    "dev": true,
-                    "requires": {
-                        "domelementtype": "^2.2.0"
-                    }
-                }
-            }
-        },
-        "dot-case": {
-            "version": "3.0.4",
-            "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
-            "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
-            "dev": true,
-            "requires": {
-                "no-case": "^3.0.4",
-                "tslib": "^2.0.3"
-            }
-        },
-        "dotenv": {
-            "version": "10.0.0",
-            "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz",
-            "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
-            "dev": true
-        },
-        "dotenv-expand": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
-            "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==",
-            "dev": true
-        },
-        "ee-first": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
-            "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
-            "dev": true
-        },
-        "electron-to-chromium": {
-            "version": "1.4.680",
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.680.tgz",
-            "integrity": "sha512-4nToZ5jlPO14W82NkF32wyjhYqQByVaDmLy4J2/tYcAbJfgO2TKJC780Az1V13gzq4l73CJ0yuyalpXvxXXD9A==",
-            "dev": true
-        },
-        "elliptic": {
-            "version": "6.5.4",
-            "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
-            "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
-            "dev": true,
-            "requires": {
-                "bn.js": "^4.11.9",
-                "brorand": "^1.1.0",
-                "hash.js": "^1.0.0",
-                "hmac-drbg": "^1.0.1",
-                "inherits": "^2.0.4",
-                "minimalistic-assert": "^1.0.1",
-                "minimalistic-crypto-utils": "^1.0.1"
-            },
-            "dependencies": {
-                "bn.js": {
-                    "version": "4.12.0",
-                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-                    "dev": true
-                }
-            }
-        },
-        "emittery": {
-            "version": "0.13.1",
-            "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
-            "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
-            "dev": true
-        },
-        "emoji-regex": {
-            "version": "8.0.0",
-            "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-            "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-            "dev": true
-        },
-        "emojis-list": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
-            "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
-            "dev": true
-        },
-        "encodeurl": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-            "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
-            "dev": true
-        },
-        "enhanced-resolve": {
-            "version": "5.15.0",
-            "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
-            "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
-            "dev": true,
-            "requires": {
-                "graceful-fs": "^4.2.4",
-                "tapable": "^2.2.0"
-            }
-        },
-        "entities": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
-            "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
-            "dev": true
-        },
-        "envinfo": {
-            "version": "7.10.0",
-            "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz",
-            "integrity": "sha512-ZtUjZO6l5mwTHvc1L9+1q5p/R3wTopcfqMW8r5t8SJSKqeVI/LtajORwRFEKpEFuekjD0VBjwu1HMxL4UalIRw==",
-            "dev": true
-        },
-        "error-ex": {
-            "version": "1.3.2",
-            "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
-            "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
-            "dev": true,
-            "requires": {
-                "is-arrayish": "^0.2.1"
-            }
-        },
-        "es-abstract": {
-            "version": "1.22.1",
-            "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz",
-            "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==",
-            "dev": true,
-            "requires": {
-                "array-buffer-byte-length": "^1.0.0",
-                "arraybuffer.prototype.slice": "^1.0.1",
-                "available-typed-arrays": "^1.0.5",
-                "call-bind": "^1.0.2",
-                "es-set-tostringtag": "^2.0.1",
-                "es-to-primitive": "^1.2.1",
-                "function.prototype.name": "^1.1.5",
-                "get-intrinsic": "^1.2.1",
-                "get-symbol-description": "^1.0.0",
-                "globalthis": "^1.0.3",
-                "gopd": "^1.0.1",
-                "has": "^1.0.3",
-                "has-property-descriptors": "^1.0.0",
-                "has-proto": "^1.0.1",
-                "has-symbols": "^1.0.3",
-                "internal-slot": "^1.0.5",
-                "is-array-buffer": "^3.0.2",
-                "is-callable": "^1.2.7",
-                "is-negative-zero": "^2.0.2",
-                "is-regex": "^1.1.4",
-                "is-shared-array-buffer": "^1.0.2",
-                "is-string": "^1.0.7",
-                "is-typed-array": "^1.1.10",
-                "is-weakref": "^1.0.2",
-                "object-inspect": "^1.12.3",
-                "object-keys": "^1.1.1",
-                "object.assign": "^4.1.4",
-                "regexp.prototype.flags": "^1.5.0",
-                "safe-array-concat": "^1.0.0",
-                "safe-regex-test": "^1.0.0",
-                "string.prototype.trim": "^1.2.7",
-                "string.prototype.trimend": "^1.0.6",
-                "string.prototype.trimstart": "^1.0.6",
-                "typed-array-buffer": "^1.0.0",
-                "typed-array-byte-length": "^1.0.0",
-                "typed-array-byte-offset": "^1.0.0",
-                "typed-array-length": "^1.0.4",
-                "unbox-primitive": "^1.0.2",
-                "which-typed-array": "^1.1.10"
-            }
-        },
-        "es-define-property": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
-            "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
-            "requires": {
-                "get-intrinsic": "^1.2.4"
-            }
-        },
-        "es-errors": {
-            "version": "1.3.0",
-            "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
-            "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="
-        },
-        "es-get-iterator": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
-            "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.1.3",
-                "has-symbols": "^1.0.3",
-                "is-arguments": "^1.1.1",
-                "is-map": "^2.0.2",
-                "is-set": "^2.0.2",
-                "is-string": "^1.0.7",
-                "isarray": "^2.0.5",
-                "stop-iteration-iterator": "^1.0.0"
-            },
-            "dependencies": {
-                "isarray": {
-                    "version": "2.0.5",
-                    "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-                    "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-                    "dev": true
-                }
-            }
-        },
-        "es-iterator-helpers": {
-            "version": "1.0.14",
-            "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz",
-            "integrity": "sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw==",
-            "dev": true,
-            "requires": {
-                "asynciterator.prototype": "^1.0.0",
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "es-set-tostringtag": "^2.0.1",
-                "function-bind": "^1.1.1",
-                "get-intrinsic": "^1.2.1",
-                "globalthis": "^1.0.3",
-                "has-property-descriptors": "^1.0.0",
-                "has-proto": "^1.0.1",
-                "has-symbols": "^1.0.3",
-                "internal-slot": "^1.0.5",
-                "iterator.prototype": "^1.1.0",
-                "safe-array-concat": "^1.0.0"
-            }
-        },
-        "es-module-lexer": {
-            "version": "1.3.0",
-            "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz",
-            "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==",
-            "dev": true
-        },
-        "es-set-tostringtag": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
-            "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
-            "dev": true,
-            "requires": {
-                "get-intrinsic": "^1.1.3",
-                "has": "^1.0.3",
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "es-shim-unscopables": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
-            "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
-            "dev": true,
-            "requires": {
-                "has": "^1.0.3"
-            }
-        },
-        "es-to-primitive": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
-            "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
-            "dev": true,
-            "requires": {
-                "is-callable": "^1.1.4",
-                "is-date-object": "^1.0.1",
-                "is-symbol": "^1.0.2"
-            }
-        },
-        "escalade": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-            "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
-            "dev": true
-        },
-        "escape-html": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-            "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
-            "dev": true
-        },
-        "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==",
-            "dev": true
-        },
-        "escodegen": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
-            "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
-            "dev": true,
-            "requires": {
-                "esprima": "^4.0.1",
-                "estraverse": "^5.2.0",
-                "esutils": "^2.0.2",
-                "source-map": "~0.6.1"
-            }
-        },
-        "eslint": {
-            "version": "8.48.0",
-            "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz",
-            "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==",
-            "dev": true,
-            "requires": {
-                "@eslint-community/eslint-utils": "^4.2.0",
-                "@eslint-community/regexpp": "^4.6.1",
-                "@eslint/eslintrc": "^2.1.2",
-                "@eslint/js": "8.48.0",
-                "@humanwhocodes/config-array": "^0.11.10",
-                "@humanwhocodes/module-importer": "^1.0.1",
-                "@nodelib/fs.walk": "^1.2.8",
-                "ajv": "^6.12.4",
-                "chalk": "^4.0.0",
-                "cross-spawn": "^7.0.2",
-                "debug": "^4.3.2",
-                "doctrine": "^3.0.0",
-                "escape-string-regexp": "^4.0.0",
-                "eslint-scope": "^7.2.2",
-                "eslint-visitor-keys": "^3.4.3",
-                "espree": "^9.6.1",
-                "esquery": "^1.4.2",
-                "esutils": "^2.0.2",
-                "fast-deep-equal": "^3.1.3",
-                "file-entry-cache": "^6.0.1",
-                "find-up": "^5.0.0",
-                "glob-parent": "^6.0.2",
-                "globals": "^13.19.0",
-                "graphemer": "^1.4.0",
-                "ignore": "^5.2.0",
-                "imurmurhash": "^0.1.4",
-                "is-glob": "^4.0.0",
-                "is-path-inside": "^3.0.3",
-                "js-yaml": "^4.1.0",
-                "json-stable-stringify-without-jsonify": "^1.0.1",
-                "levn": "^0.4.1",
-                "lodash.merge": "^4.6.2",
-                "minimatch": "^3.1.2",
-                "natural-compare": "^1.4.0",
-                "optionator": "^0.9.3",
-                "strip-ansi": "^6.0.1",
-                "text-table": "^0.2.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "escape-string-regexp": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-                    "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-                    "dev": true
-                },
-                "eslint-scope": {
-                    "version": "7.2.2",
-                    "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
-                    "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
-                    "dev": true,
-                    "requires": {
-                        "esrecurse": "^4.3.0",
-                        "estraverse": "^5.2.0"
-                    }
-                },
-                "eslint-visitor-keys": {
-                    "version": "3.4.3",
-                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-                    "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
-                    "dev": true
-                },
-                "globals": {
-                    "version": "13.21.0",
-                    "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz",
-                    "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==",
-                    "dev": true,
-                    "requires": {
-                        "type-fest": "^0.20.2"
-                    }
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "eslint-import-resolver-node": {
-            "version": "0.3.9",
-            "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
-            "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
-            "dev": true,
-            "requires": {
-                "debug": "^3.2.7",
-                "is-core-module": "^2.13.0",
-                "resolve": "^1.22.4"
-            },
-            "dependencies": {
-                "debug": {
-                    "version": "3.2.7",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-                    "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "^2.1.1"
-                    }
-                }
-            }
-        },
-        "eslint-module-utils": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz",
-            "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==",
-            "dev": true,
-            "requires": {
-                "debug": "^3.2.7"
-            },
-            "dependencies": {
-                "debug": {
-                    "version": "3.2.7",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-                    "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "^2.1.1"
-                    }
-                }
-            }
-        },
-        "eslint-plugin-import": {
-            "version": "2.28.1",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz",
-            "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==",
-            "dev": true,
-            "requires": {
-                "array-includes": "^3.1.6",
-                "array.prototype.findlastindex": "^1.2.2",
-                "array.prototype.flat": "^1.3.1",
-                "array.prototype.flatmap": "^1.3.1",
-                "debug": "^3.2.7",
-                "doctrine": "^2.1.0",
-                "eslint-import-resolver-node": "^0.3.7",
-                "eslint-module-utils": "^2.8.0",
-                "has": "^1.0.3",
-                "is-core-module": "^2.13.0",
-                "is-glob": "^4.0.3",
-                "minimatch": "^3.1.2",
-                "object.fromentries": "^2.0.6",
-                "object.groupby": "^1.0.0",
-                "object.values": "^1.1.6",
-                "semver": "^6.3.1",
-                "tsconfig-paths": "^3.14.2"
-            },
-            "dependencies": {
-                "debug": {
-                    "version": "3.2.7",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-                    "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "^2.1.1"
-                    }
-                },
-                "doctrine": {
-                    "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
-                    "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
-                    "dev": true,
-                    "requires": {
-                        "esutils": "^2.0.2"
-                    }
-                }
-            }
-        },
-        "eslint-plugin-react": {
-            "version": "7.33.2",
-            "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz",
-            "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==",
-            "dev": true,
-            "requires": {
-                "array-includes": "^3.1.6",
-                "array.prototype.flatmap": "^1.3.1",
-                "array.prototype.tosorted": "^1.1.1",
-                "doctrine": "^2.1.0",
-                "es-iterator-helpers": "^1.0.12",
-                "estraverse": "^5.3.0",
-                "jsx-ast-utils": "^2.4.1 || ^3.0.0",
-                "minimatch": "^3.1.2",
-                "object.entries": "^1.1.6",
-                "object.fromentries": "^2.0.6",
-                "object.hasown": "^1.1.2",
-                "object.values": "^1.1.6",
-                "prop-types": "^15.8.1",
-                "resolve": "^2.0.0-next.4",
-                "semver": "^6.3.1",
-                "string.prototype.matchall": "^4.0.8"
-            },
-            "dependencies": {
-                "doctrine": {
-                    "version": "2.1.0",
-                    "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
-                    "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
-                    "dev": true,
-                    "requires": {
-                        "esutils": "^2.0.2"
-                    }
-                },
-                "resolve": {
-                    "version": "2.0.0-next.4",
-                    "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
-                    "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
-                    "dev": true,
-                    "requires": {
-                        "is-core-module": "^2.9.0",
-                        "path-parse": "^1.0.7",
-                        "supports-preserve-symlinks-flag": "^1.0.0"
-                    }
-                }
-            }
-        },
-        "eslint-scope": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
-            "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
-            "dev": true,
-            "requires": {
-                "esrecurse": "^4.3.0",
-                "estraverse": "^4.1.1"
-            },
-            "dependencies": {
-                "estraverse": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-                    "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
-                    "dev": true
-                }
-            }
-        },
-        "eslint-visitor-keys": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-            "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
-            "dev": true
-        },
-        "espree": {
-            "version": "9.6.1",
-            "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
-            "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
-            "dev": true,
-            "requires": {
-                "acorn": "^8.9.0",
-                "acorn-jsx": "^5.3.2",
-                "eslint-visitor-keys": "^3.4.1"
-            },
-            "dependencies": {
-                "eslint-visitor-keys": {
-                    "version": "3.4.3",
-                    "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-                    "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
-                    "dev": true
-                }
-            }
-        },
-        "esprima": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-            "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-            "dev": true
-        },
-        "esquery": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
-            "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
-            "dev": true,
-            "requires": {
-                "estraverse": "^5.1.0"
-            }
-        },
-        "esrecurse": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
-            "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
-            "dev": true,
-            "requires": {
-                "estraverse": "^5.2.0"
-            }
-        },
-        "estraverse": {
-            "version": "5.3.0",
-            "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-            "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-            "dev": true
-        },
-        "esutils": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-            "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
-            "dev": true
-        },
-        "etag": {
-            "version": "1.8.1",
-            "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-            "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
-            "dev": true
-        },
-        "eventemitter3": {
-            "version": "4.0.7",
-            "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
-            "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
-        },
-        "events": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
-            "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
-            "dev": true
-        },
-        "evp_bytestokey": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
-            "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
-            "dev": true,
-            "requires": {
-                "md5.js": "^1.3.4",
-                "safe-buffer": "^5.1.1"
-            }
-        },
-        "execa": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
-            "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
-            "dev": true,
-            "requires": {
-                "cross-spawn": "^7.0.3",
-                "get-stream": "^6.0.0",
-                "human-signals": "^2.1.0",
-                "is-stream": "^2.0.0",
-                "merge-stream": "^2.0.0",
-                "npm-run-path": "^4.0.1",
-                "onetime": "^5.1.2",
-                "signal-exit": "^3.0.3",
-                "strip-final-newline": "^2.0.0"
-            }
-        },
-        "exit": {
-            "version": "0.1.2",
-            "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
-            "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
-            "dev": true
-        },
-        "expect": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
-            "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
-            "dev": true,
-            "requires": {
-                "@jest/expect-utils": "^29.7.0",
-                "jest-get-type": "^29.6.3",
-                "jest-matcher-utils": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-util": "^29.7.0"
-            }
-        },
-        "express": {
-            "version": "4.18.2",
-            "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
-            "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
-            "dev": true,
-            "requires": {
-                "accepts": "~1.3.8",
-                "array-flatten": "1.1.1",
-                "body-parser": "1.20.1",
-                "content-disposition": "0.5.4",
-                "content-type": "~1.0.4",
-                "cookie": "0.5.0",
-                "cookie-signature": "1.0.6",
-                "debug": "2.6.9",
-                "depd": "2.0.0",
-                "encodeurl": "~1.0.2",
-                "escape-html": "~1.0.3",
-                "etag": "~1.8.1",
-                "finalhandler": "1.2.0",
-                "fresh": "0.5.2",
-                "http-errors": "2.0.0",
-                "merge-descriptors": "1.0.1",
-                "methods": "~1.1.2",
-                "on-finished": "2.4.1",
-                "parseurl": "~1.3.3",
-                "path-to-regexp": "0.1.7",
-                "proxy-addr": "~2.0.7",
-                "qs": "6.11.0",
-                "range-parser": "~1.2.1",
-                "safe-buffer": "5.2.1",
-                "send": "0.18.0",
-                "serve-static": "1.15.0",
-                "setprototypeof": "1.2.0",
-                "statuses": "2.0.1",
-                "type-is": "~1.6.18",
-                "utils-merge": "1.0.1",
-                "vary": "~1.1.2"
-            },
-            "dependencies": {
-                "array-flatten": {
-                    "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
-                    "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
-                    "dev": true
-                },
-                "debug": {
-                    "version": "2.6.9",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-                    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "2.0.0"
-                    }
-                },
-                "ms": {
-                    "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                    "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-                    "dev": true
-                },
-                "qs": {
-                    "version": "6.11.0",
-                    "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
-                    "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
-                    "dev": true,
-                    "requires": {
-                        "side-channel": "^1.0.4"
-                    }
-                }
-            }
-        },
-        "fast-deep-equal": {
-            "version": "3.1.3",
-            "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-            "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-            "dev": true
-        },
-        "fast-equals": {
-            "version": "5.0.1",
-            "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz",
-            "integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ=="
-        },
-        "fast-glob": {
-            "version": "3.3.1",
-            "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
-            "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
-            "dev": true,
-            "requires": {
-                "@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"
-            },
-            "dependencies": {
-                "glob-parent": {
-                    "version": "5.1.2",
-                    "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-                    "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-                    "dev": true,
-                    "requires": {
-                        "is-glob": "^4.0.1"
-                    }
-                }
-            }
-        },
-        "fast-json-stable-stringify": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
-            "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-            "dev": true
-        },
-        "fast-levenshtein": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-            "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
-            "dev": true
-        },
-        "fastest-levenshtein": {
-            "version": "1.0.16",
-            "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
-            "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
-            "dev": true
-        },
-        "fastq": {
-            "version": "1.15.0",
-            "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
-            "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
-            "dev": true,
-            "requires": {
-                "reusify": "^1.0.4"
-            }
-        },
-        "faye-websocket": {
-            "version": "0.11.4",
-            "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
-            "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
-            "dev": true,
-            "requires": {
-                "websocket-driver": ">=0.5.1"
-            }
-        },
-        "fb-watchman": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
-            "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
-            "dev": true,
-            "requires": {
-                "bser": "2.1.1"
-            }
-        },
-        "file-entry-cache": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
-            "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
-            "dev": true,
-            "requires": {
-                "flat-cache": "^3.0.4"
-            }
-        },
-        "file-loader": {
-            "version": "6.2.0",
-            "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
-            "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==",
-            "dev": true,
-            "requires": {
-                "loader-utils": "^2.0.0",
-                "schema-utils": "^3.0.0"
-            },
-            "dependencies": {
-                "schema-utils": {
-                    "version": "3.3.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-                    "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.8",
-                        "ajv": "^6.12.5",
-                        "ajv-keywords": "^3.5.2"
-                    }
-                }
-            }
-        },
-        "file-saver": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
-            "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
-        },
-        "file-type": {
-            "version": "12.4.2",
-            "resolved": "https://registry.npmjs.org/file-type/-/file-type-12.4.2.tgz",
-            "integrity": "sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg==",
-            "dev": true
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "to-regex-range": "^5.0.1"
-            }
-        },
-        "finalhandler": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
-            "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
-            "dev": true,
-            "requires": {
-                "debug": "2.6.9",
-                "encodeurl": "~1.0.2",
-                "escape-html": "~1.0.3",
-                "on-finished": "2.4.1",
-                "parseurl": "~1.3.3",
-                "statuses": "2.0.1",
-                "unpipe": "~1.0.0"
-            },
-            "dependencies": {
-                "debug": {
-                    "version": "2.6.9",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-                    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "2.0.0"
-                    }
-                },
-                "ms": {
-                    "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                    "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-                    "dev": true
-                }
-            }
-        },
-        "find-cache-dir": {
-            "version": "3.3.2",
-            "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
-            "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
-            "dev": true,
-            "requires": {
-                "commondir": "^1.0.1",
-                "make-dir": "^3.0.2",
-                "pkg-dir": "^4.1.0"
-            }
-        },
-        "find-up": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-            "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-            "dev": true,
-            "requires": {
-                "locate-path": "^6.0.0",
-                "path-exists": "^4.0.0"
-            }
-        },
-        "flat-cache": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz",
-            "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==",
-            "dev": true,
-            "requires": {
-                "flatted": "^3.2.7",
-                "keyv": "^4.5.3",
-                "rimraf": "^3.0.2"
-            }
-        },
-        "flatted": {
-            "version": "3.2.7",
-            "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
-            "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
-            "dev": true
-        },
-        "follow-redirects": {
-            "version": "1.15.2",
-            "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
-            "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
-            "dev": true
-        },
-        "for-each": {
-            "version": "0.3.3",
-            "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
-            "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
-            "dev": true,
-            "requires": {
-                "is-callable": "^1.1.3"
-            }
-        },
-        "form-data": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
-            "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
-            "dev": true,
-            "requires": {
-                "asynckit": "^0.4.0",
-                "combined-stream": "^1.0.8",
-                "mime-types": "^2.1.12"
-            }
-        },
-        "formik": {
-            "version": "2.4.3",
-            "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.3.tgz",
-            "integrity": "sha512-2Dy79Szw3zlXmZiokUdKsn+n1ow4G8hRrC/n92cOWHNTWXCRpQXlyvz6HcjW7aSQZrldytvDOavYjhfmDnUq8Q==",
-            "requires": {
-                "deepmerge": "^2.1.1",
-                "hoist-non-react-statics": "^3.3.0",
-                "lodash": "^4.17.21",
-                "lodash-es": "^4.17.21",
-                "react-fast-compare": "^2.0.1",
-                "tiny-warning": "^1.0.2",
-                "tslib": "^2.0.0"
-            }
-        },
-        "forwarded": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
-            "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
-            "dev": true
-        },
-        "fraction.js": {
-            "version": "4.3.6",
-            "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz",
-            "integrity": "sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==",
-            "dev": true
-        },
-        "fresh": {
-            "version": "0.5.2",
-            "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-            "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
-            "dev": true
-        },
-        "fs-extra": {
-            "version": "10.1.0",
-            "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
-            "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
-            "dev": true,
-            "requires": {
-                "graceful-fs": "^4.2.0",
-                "jsonfile": "^6.0.1",
-                "universalify": "^2.0.0"
-            }
-        },
-        "fs-monkey": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.4.tgz",
-            "integrity": "sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ==",
-            "dev": true
-        },
-        "fs.realpath": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-            "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-            "dev": true
-        },
-        "fsevents": {
-            "version": "2.3.3",
-            "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
-            "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
-            "dev": true,
-            "optional": true
-        },
-        "function-bind": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
-            "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
-        },
-        "function.prototype.name": {
-            "version": "1.1.6",
-            "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
-            "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "functions-have-names": "^1.2.3"
-            }
-        },
-        "functions-have-names": {
-            "version": "1.2.3",
-            "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
-            "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
-            "dev": true
-        },
-        "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==",
-            "dev": true
-        },
-        "get-caller-file": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-            "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-            "dev": true
-        },
-        "get-intrinsic": {
-            "version": "1.2.4",
-            "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
-            "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
-            "requires": {
-                "es-errors": "^1.3.0",
-                "function-bind": "^1.1.2",
-                "has-proto": "^1.0.1",
-                "has-symbols": "^1.0.3",
-                "hasown": "^2.0.0"
-            }
-        },
-        "get-package-type": {
-            "version": "0.1.0",
-            "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
-            "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
-            "dev": true
-        },
-        "get-stream": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
-            "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
-            "dev": true
-        },
-        "get-symbol-description": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
-            "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.1.1"
-            }
-        },
-        "glob": {
-            "version": "7.2.3",
-            "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-            "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-            "dev": true,
-            "requires": {
-                "fs.realpath": "^1.0.0",
-                "inflight": "^1.0.4",
-                "inherits": "2",
-                "minimatch": "^3.1.1",
-                "once": "^1.3.0",
-                "path-is-absolute": "^1.0.0"
-            }
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "is-glob": "^4.0.3"
-            }
-        },
-        "glob-to-regexp": {
-            "version": "0.4.1",
-            "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
-            "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
-            "dev": true
-        },
-        "globals": {
-            "version": "11.12.0",
-            "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-            "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-            "dev": true
-        },
-        "globalthis": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
-            "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
-            "dev": true,
-            "requires": {
-                "define-properties": "^1.1.3"
-            }
-        },
-        "globby": {
-            "version": "10.0.2",
-            "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz",
-            "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==",
-            "dev": true,
-            "requires": {
-                "@types/glob": "^7.1.1",
-                "array-union": "^2.1.0",
-                "dir-glob": "^3.0.1",
-                "fast-glob": "^3.0.3",
-                "glob": "^7.1.3",
-                "ignore": "^5.1.1",
-                "merge2": "^1.2.3",
-                "slash": "^3.0.0"
-            }
-        },
-        "gopd": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
-            "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
-            "requires": {
-                "get-intrinsic": "^1.1.3"
-            }
-        },
-        "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==",
-            "dev": true
-        },
-        "graphemer": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
-            "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
-            "dev": true
-        },
-        "growly": {
-            "version": "1.3.0",
-            "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
-            "integrity": "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==",
-            "dev": true
-        },
-        "handle-thing": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
-            "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
-            "dev": true
-        },
-        "has": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-            "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-            "dev": true,
-            "requires": {
-                "function-bind": "^1.1.1"
-            }
-        },
-        "has-bigints": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
-            "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
-            "dev": true
-        },
-        "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==",
-            "dev": true
-        },
-        "has-property-descriptors": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
-            "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
-            "requires": {
-                "es-define-property": "^1.0.0"
-            }
-        },
-        "has-proto": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
-            "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="
-        },
-        "has-symbols": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
-            "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
-        },
-        "has-tostringtag": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
-            "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
-            "dev": true,
-            "requires": {
-                "has-symbols": "^1.0.3"
-            }
-        },
-        "hash-base": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
-            "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
-            "dev": true,
-            "requires": {
-                "inherits": "^2.0.4",
-                "readable-stream": "^3.6.0",
-                "safe-buffer": "^5.2.0"
-            },
-            "dependencies": {
-                "readable-stream": {
-                    "version": "3.6.2",
-                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-                    "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
-                    "dev": true,
-                    "requires": {
-                        "inherits": "^2.0.3",
-                        "string_decoder": "^1.1.1",
-                        "util-deprecate": "^1.0.1"
-                    }
-                }
-            }
-        },
-        "hash-sum": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
-            "integrity": "sha512-fUs4B4L+mlt8/XAtSOGMUO1TXmAelItBPtJG7CyHJfYTdDjwisntGO2JQz7oUsatOY9o68+57eziUVNw/mRHmA==",
-            "dev": true
-        },
-        "hash.js": {
-            "version": "1.1.7",
-            "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
-            "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
-            "dev": true,
-            "requires": {
-                "inherits": "^2.0.3",
-                "minimalistic-assert": "^1.0.1"
-            }
-        },
-        "hasown": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz",
-            "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==",
-            "requires": {
-                "function-bind": "^1.1.2"
-            }
-        },
-        "he": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
-            "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
-            "dev": true
-        },
-        "hmac-drbg": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
-            "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
-            "dev": true,
-            "requires": {
-                "hash.js": "^1.0.3",
-                "minimalistic-assert": "^1.0.0",
-                "minimalistic-crypto-utils": "^1.0.1"
-            }
-        },
-        "hoist-non-react-statics": {
-            "version": "3.3.2",
-            "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
-            "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
-            "requires": {
-                "react-is": "^16.7.0"
-            }
-        },
-        "hpack.js": {
-            "version": "2.1.6",
-            "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
-            "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==",
-            "dev": true,
-            "requires": {
-                "inherits": "^2.0.1",
-                "obuf": "^1.0.0",
-                "readable-stream": "^2.0.1",
-                "wbuf": "^1.1.0"
-            }
-        },
-        "html-encoding-sniffer": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
-            "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==",
-            "dev": true,
-            "requires": {
-                "whatwg-encoding": "^2.0.0"
-            }
-        },
-        "html-entities": {
-            "version": "2.4.0",
-            "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz",
-            "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==",
-            "dev": true
-        },
-        "html-escaper": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
-            "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
-            "dev": true
-        },
-        "html-loader": {
-            "version": "1.3.2",
-            "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-1.3.2.tgz",
-            "integrity": "sha512-DEkUwSd0sijK5PF3kRWspYi56XP7bTNkyg5YWSzBdjaSDmvCufep5c4Vpb3PBf6lUL0YPtLwBfy9fL0t5hBAGA==",
-            "dev": true,
-            "requires": {
-                "html-minifier-terser": "^5.1.1",
-                "htmlparser2": "^4.1.0",
-                "loader-utils": "^2.0.0",
-                "schema-utils": "^3.0.0"
-            },
-            "dependencies": {
-                "schema-utils": {
-                    "version": "3.3.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-                    "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.8",
-                        "ajv": "^6.12.5",
-                        "ajv-keywords": "^3.5.2"
-                    }
-                }
-            }
-        },
-        "html-minifier-terser": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
-            "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==",
-            "dev": true,
-            "requires": {
-                "camel-case": "^4.1.1",
-                "clean-css": "^4.2.3",
-                "commander": "^4.1.1",
-                "he": "^1.2.0",
-                "param-case": "^3.0.3",
-                "relateurl": "^0.2.7",
-                "terser": "^4.6.3"
-            },
-            "dependencies": {
-                "clean-css": {
-                    "version": "4.2.4",
-                    "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz",
-                    "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==",
-                    "dev": true,
-                    "requires": {
-                        "source-map": "~0.6.0"
-                    }
-                },
-                "commander": {
-                    "version": "4.1.1",
-                    "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
-                    "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
-                    "dev": true
-                },
-                "terser": {
-                    "version": "4.8.1",
-                    "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz",
-                    "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==",
-                    "dev": true,
-                    "requires": {
-                        "commander": "^2.20.0",
-                        "source-map": "~0.6.1",
-                        "source-map-support": "~0.5.12"
-                    },
-                    "dependencies": {
-                        "commander": {
-                            "version": "2.20.3",
-                            "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-                            "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-                            "dev": true
-                        }
-                    }
-                }
-            }
-        },
-        "html-parse-stringify": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
-            "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
-            "requires": {
-                "void-elements": "3.1.0"
-            }
-        },
-        "htmlparser2": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
-            "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
-            "dev": true,
-            "requires": {
-                "domelementtype": "^2.0.1",
-                "domhandler": "^3.0.0",
-                "domutils": "^2.0.0",
-                "entities": "^2.0.0"
-            }
-        },
-        "http-deceiver": {
-            "version": "1.2.7",
-            "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
-            "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==",
-            "dev": true
-        },
-        "http-errors": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
-            "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
-            "dev": true,
-            "requires": {
-                "depd": "2.0.0",
-                "inherits": "2.0.4",
-                "setprototypeof": "1.2.0",
-                "statuses": "2.0.1",
-                "toidentifier": "1.0.1"
-            }
-        },
-        "http-parser-js": {
-            "version": "0.5.8",
-            "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
-            "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
-            "dev": true
-        },
-        "http-proxy": {
-            "version": "1.18.1",
-            "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
-            "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
-            "dev": true,
-            "requires": {
-                "eventemitter3": "^4.0.0",
-                "follow-redirects": "^1.0.0",
-                "requires-port": "^1.0.0"
-            }
-        },
-        "http-proxy-agent": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz",
-            "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==",
-            "dev": true,
-            "requires": {
-                "@tootallnate/once": "2",
-                "agent-base": "6",
-                "debug": "4"
-            }
-        },
-        "http-proxy-middleware": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz",
-            "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==",
-            "dev": true,
-            "requires": {
-                "@types/http-proxy": "^1.17.8",
-                "http-proxy": "^1.18.1",
-                "is-glob": "^4.0.1",
-                "is-plain-obj": "^3.0.0",
-                "micromatch": "^4.0.2"
-            }
-        },
-        "https-browserify": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
-            "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
-            "dev": true
-        },
-        "https-proxy-agent": {
-            "version": "5.0.1",
-            "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
-            "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
-            "dev": true,
-            "requires": {
-                "agent-base": "6",
-                "debug": "4"
-            }
-        },
-        "human-signals": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
-            "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
-            "dev": true
-        },
-        "i18next": {
-            "version": "23.4.9",
-            "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.4.9.tgz",
-            "integrity": "sha512-F8YQ29LD6FvWS/aOYbZ4WqjDEuQZmug8akAM0QOcAtR+EuHHlBYf/JpsjeqUDdYiClmj2zE9rI9ZUWzN7W+trQ==",
-            "requires": {
-                "@babel/runtime": "^7.22.5"
-            }
-        },
-        "i18next-browser-languagedetector": {
-            "version": "7.1.0",
-            "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.1.0.tgz",
-            "integrity": "sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA==",
-            "requires": {
-                "@babel/runtime": "^7.19.4"
-            }
-        },
-        "iconv-lite": {
-            "version": "0.4.24",
-            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-            "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-            "dev": true,
-            "requires": {
-                "safer-buffer": ">= 2.1.2 < 3"
-            }
-        },
-        "icss-utils": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
-            "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
-            "dev": true,
-            "requires": {}
-        },
-        "ieee754": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
-            "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
-            "dev": true
-        },
-        "ignore": {
-            "version": "5.2.4",
-            "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
-            "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
-            "dev": true
-        },
-        "imagemin": {
-            "version": "7.0.1",
-            "resolved": "https://registry.npmjs.org/imagemin/-/imagemin-7.0.1.tgz",
-            "integrity": "sha512-33AmZ+xjZhg2JMCe+vDf6a9mzWukE7l+wAtesjE7KyteqqKjzxv7aVQeWnul1Ve26mWvEQqyPwl0OctNBfSR9w==",
-            "dev": true,
-            "requires": {
-                "file-type": "^12.0.0",
-                "globby": "^10.0.0",
-                "graceful-fs": "^4.2.2",
-                "junk": "^3.1.0",
-                "make-dir": "^3.0.0",
-                "p-pipe": "^3.0.0",
-                "replace-ext": "^1.0.0"
-            }
-        },
-        "img-loader": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/img-loader/-/img-loader-4.0.0.tgz",
-            "integrity": "sha512-UwRcPQdwdOyEHyCxe1V9s9YFwInwEWCpoO+kJGfIqDrBDqA8jZUsEZTxQ0JteNPGw/Gupmwesk2OhLTcnw6tnQ==",
-            "dev": true,
-            "requires": {
-                "loader-utils": "^1.1.0"
-            },
-            "dependencies": {
-                "json5": {
-                    "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-                    "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-                    "dev": true,
-                    "requires": {
-                        "minimist": "^1.2.0"
-                    }
-                },
-                "loader-utils": {
-                    "version": "1.4.2",
-                    "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
-                    "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
-                    "dev": true,
-                    "requires": {
-                        "big.js": "^5.2.2",
-                        "emojis-list": "^3.0.0",
-                        "json5": "^1.0.1"
-                    }
-                }
-            }
-        },
-        "immediate": {
-            "version": "3.0.6",
-            "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
-            "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="
-        },
-        "immutable": {
-            "version": "4.3.4",
-            "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
-            "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==",
-            "dev": true
-        },
-        "import-fresh": {
-            "version": "3.3.0",
-            "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
-            "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
-            "dev": true,
-            "requires": {
-                "parent-module": "^1.0.0",
-                "resolve-from": "^4.0.0"
-            }
-        },
-        "import-local": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
-            "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
-            "dev": true,
-            "requires": {
-                "pkg-dir": "^4.2.0",
-                "resolve-cwd": "^3.0.0"
-            }
-        },
-        "imurmurhash": {
-            "version": "0.1.4",
-            "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-            "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
-            "dev": true
-        },
-        "indent-string": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
-            "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
-            "dev": true
-        },
-        "inflight": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-            "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-            "dev": true,
-            "requires": {
-                "once": "^1.3.0",
-                "wrappy": "1"
-            }
-        },
-        "inherits": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-            "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-            "dev": true
-        },
-        "internal-slot": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
-            "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
-            "dev": true,
-            "requires": {
-                "get-intrinsic": "^1.2.0",
-                "has": "^1.0.3",
-                "side-channel": "^1.0.4"
-            }
-        },
-        "internmap": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
-            "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="
-        },
-        "interpret": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
-            "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
-            "dev": true
-        },
-        "invariant": {
-            "version": "2.2.4",
-            "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
-            "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
-            "requires": {
-                "loose-envify": "^1.0.0"
-            }
-        },
-        "ipaddr.js": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz",
-            "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==",
-            "dev": true
-        },
-        "is-arguments": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
-            "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "is-array-buffer": {
-            "version": "3.0.2",
-            "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
-            "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.2.0",
-                "is-typed-array": "^1.1.10"
-            }
-        },
-        "is-arrayish": {
-            "version": "0.2.1",
-            "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-            "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
-            "dev": true
-        },
-        "is-async-function": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
-            "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
-            "dev": true,
-            "requires": {
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "is-bigint": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
-            "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
-            "dev": true,
-            "requires": {
-                "has-bigints": "^1.0.1"
-            }
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "binary-extensions": "^2.0.0"
-            }
-        },
-        "is-boolean-object": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
-            "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "is-buffer": {
-            "version": "1.1.6",
-            "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
-            "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
-            "dev": true
-        },
-        "is-callable": {
-            "version": "1.2.7",
-            "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
-            "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
-            "dev": true
-        },
-        "is-core-module": {
-            "version": "2.13.0",
-            "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
-            "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
-            "dev": true,
-            "requires": {
-                "has": "^1.0.3"
-            }
-        },
-        "is-date-object": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
-            "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
-            "dev": true,
-            "requires": {
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "is-docker": {
-            "version": "2.2.1",
-            "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
-            "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
-            "dev": true
-        },
-        "is-extglob": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-            "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
-            "dev": true
-        },
-        "is-finalizationregistry": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz",
-            "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2"
-            }
-        },
-        "is-fullwidth-code-point": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-            "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-            "dev": true
-        },
-        "is-generator-fn": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
-            "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
-            "dev": true
-        },
-        "is-generator-function": {
-            "version": "1.0.10",
-            "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
-            "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
-            "dev": true,
-            "requires": {
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "is-glob": {
-            "version": "4.0.3",
-            "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-            "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-            "dev": true,
-            "requires": {
-                "is-extglob": "^2.1.1"
-            }
-        },
-        "is-map": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
-            "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
-            "dev": true
-        },
-        "is-negative-zero": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
-            "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
-            "dev": true
-        },
-        "is-number": {
-            "version": "7.0.0",
-            "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-            "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-            "dev": true
-        },
-        "is-number-object": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
-            "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
-            "dev": true,
-            "requires": {
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "is-path-inside": {
-            "version": "3.0.3",
-            "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-            "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-            "dev": true
-        },
-        "is-plain-obj": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz",
-            "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==",
-            "dev": true
-        },
-        "is-plain-object": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
-            "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
-            "dev": true,
-            "requires": {
-                "isobject": "^3.0.1"
-            }
-        },
-        "is-potential-custom-element-name": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
-            "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
-            "dev": true
-        },
-        "is-regex": {
-            "version": "1.1.4",
-            "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
-            "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "is-set": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
-            "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
-            "dev": true
-        },
-        "is-shared-array-buffer": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
-            "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2"
-            }
-        },
-        "is-stream": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-            "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
-            "dev": true
-        },
-        "is-string": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
-            "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
-            "dev": true,
-            "requires": {
-                "has-tostringtag": "^1.0.0"
-            }
-        },
-        "is-symbol": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
-            "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
-            "dev": true,
-            "requires": {
-                "has-symbols": "^1.0.2"
-            }
-        },
-        "is-typed-array": {
-            "version": "1.1.12",
-            "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz",
-            "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
-            "dev": true,
-            "requires": {
-                "which-typed-array": "^1.1.11"
-            }
-        },
-        "is-weakmap": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz",
-            "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==",
-            "dev": true
-        },
-        "is-weakref": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
-            "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2"
-            }
-        },
-        "is-weakset": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz",
-            "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.1.1"
-            }
-        },
-        "is-wsl": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
-            "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
-            "dev": true,
-            "requires": {
-                "is-docker": "^2.0.0"
-            }
-        },
-        "isarray": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-            "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
-            "dev": true
-        },
-        "isexe": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-            "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
-            "dev": true
-        },
-        "isobject": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-            "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
-            "dev": true
-        },
-        "istanbul-lib-coverage": {
-            "version": "3.2.2",
-            "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
-            "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
-            "dev": true
-        },
-        "istanbul-lib-instrument": {
-            "version": "6.0.2",
-            "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz",
-            "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==",
-            "dev": true,
-            "requires": {
-                "@babel/core": "^7.23.9",
-                "@babel/parser": "^7.23.9",
-                "@istanbuljs/schema": "^0.1.3",
-                "istanbul-lib-coverage": "^3.2.0",
-                "semver": "^7.5.4"
-            },
-            "dependencies": {
-                "lru-cache": {
-                    "version": "6.0.0",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-                    "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-                    "dev": true,
-                    "requires": {
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "semver": {
-                    "version": "7.6.0",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
-                    "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
-                    "dev": true,
-                    "requires": {
-                        "lru-cache": "^6.0.0"
-                    }
-                },
-                "yallist": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-                    "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-                    "dev": true
-                }
-            }
-        },
-        "istanbul-lib-report": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
-            "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
-            "dev": true,
-            "requires": {
-                "istanbul-lib-coverage": "^3.0.0",
-                "make-dir": "^4.0.0",
-                "supports-color": "^7.1.0"
-            },
-            "dependencies": {
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "lru-cache": {
-                    "version": "6.0.0",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-                    "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-                    "dev": true,
-                    "requires": {
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "make-dir": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
-                    "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
-                    "dev": true,
-                    "requires": {
-                        "semver": "^7.5.3"
-                    }
-                },
-                "semver": {
-                    "version": "7.6.0",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
-                    "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
-                    "dev": true,
-                    "requires": {
-                        "lru-cache": "^6.0.0"
-                    }
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                },
-                "yallist": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-                    "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-                    "dev": true
-                }
-            }
-        },
-        "istanbul-lib-source-maps": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
-            "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
-            "dev": true,
-            "requires": {
-                "debug": "^4.1.1",
-                "istanbul-lib-coverage": "^3.0.0",
-                "source-map": "^0.6.1"
-            }
-        },
-        "istanbul-reports": {
-            "version": "3.1.7",
-            "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
-            "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
-            "dev": true,
-            "requires": {
-                "html-escaper": "^2.0.0",
-                "istanbul-lib-report": "^3.0.0"
-            }
-        },
-        "iterator.prototype": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.1.tgz",
-            "integrity": "sha512-9E+nePc8C9cnQldmNl6bgpTY6zI4OPRZd97fhJ/iVZ1GifIUDVV5F6x1nEDqpe8KaMEZGT4xgrwKQDxXnjOIZQ==",
-            "dev": true,
-            "requires": {
-                "define-properties": "^1.2.0",
-                "get-intrinsic": "^1.2.1",
-                "has-symbols": "^1.0.3",
-                "reflect.getprototypeof": "^1.0.3"
-            }
-        },
-        "jest": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
-            "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
-            "dev": true,
-            "requires": {
-                "@jest/core": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "import-local": "^3.0.2",
-                "jest-cli": "^29.7.0"
-            }
-        },
-        "jest-changed-files": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
-            "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
-            "dev": true,
-            "requires": {
-                "execa": "^5.0.0",
-                "jest-util": "^29.7.0",
-                "p-limit": "^3.1.0"
-            }
-        },
-        "jest-circus": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz",
-            "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
-            "dev": true,
-            "requires": {
-                "@jest/environment": "^29.7.0",
-                "@jest/expect": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "co": "^4.6.0",
-                "dedent": "^1.0.0",
-                "is-generator-fn": "^2.0.0",
-                "jest-each": "^29.7.0",
-                "jest-matcher-utils": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-runtime": "^29.7.0",
-                "jest-snapshot": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "p-limit": "^3.1.0",
-                "pretty-format": "^29.7.0",
-                "pure-rand": "^6.0.0",
-                "slash": "^3.0.0",
-                "stack-utils": "^2.0.3"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-cli": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz",
-            "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
-            "dev": true,
-            "requires": {
-                "@jest/core": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "chalk": "^4.0.0",
-                "create-jest": "^29.7.0",
-                "exit": "^0.1.2",
-                "import-local": "^3.0.2",
-                "jest-config": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-validate": "^29.7.0",
-                "yargs": "^17.3.1"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-config": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz",
-            "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
-            "dev": true,
-            "requires": {
-                "@babel/core": "^7.11.6",
-                "@jest/test-sequencer": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "babel-jest": "^29.7.0",
-                "chalk": "^4.0.0",
-                "ci-info": "^3.2.0",
-                "deepmerge": "^4.2.2",
-                "glob": "^7.1.3",
-                "graceful-fs": "^4.2.9",
-                "jest-circus": "^29.7.0",
-                "jest-environment-node": "^29.7.0",
-                "jest-get-type": "^29.6.3",
-                "jest-regex-util": "^29.6.3",
-                "jest-resolve": "^29.7.0",
-                "jest-runner": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-validate": "^29.7.0",
-                "micromatch": "^4.0.4",
-                "parse-json": "^5.2.0",
-                "pretty-format": "^29.7.0",
-                "slash": "^3.0.0",
-                "strip-json-comments": "^3.1.1"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "deepmerge": {
-                    "version": "4.3.1",
-                    "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
-                    "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-diff": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
-            "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
-            "dev": true,
-            "requires": {
-                "chalk": "^4.0.0",
-                "diff-sequences": "^29.6.3",
-                "jest-get-type": "^29.6.3",
-                "pretty-format": "^29.7.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-docblock": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz",
-            "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
-            "dev": true,
-            "requires": {
-                "detect-newline": "^3.0.0"
-            }
-        },
-        "jest-each": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz",
-            "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
-            "dev": true,
-            "requires": {
-                "@jest/types": "^29.6.3",
-                "chalk": "^4.0.0",
-                "jest-get-type": "^29.6.3",
-                "jest-util": "^29.7.0",
-                "pretty-format": "^29.7.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-environment-jsdom": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz",
-            "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==",
-            "dev": true,
-            "requires": {
-                "@jest/environment": "^29.7.0",
-                "@jest/fake-timers": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/jsdom": "^20.0.0",
-                "@types/node": "*",
-                "jest-mock": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jsdom": "^20.0.0"
-            }
-        },
-        "jest-environment-node": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
-            "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
-            "dev": true,
-            "requires": {
-                "@jest/environment": "^29.7.0",
-                "@jest/fake-timers": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "jest-mock": "^29.7.0",
-                "jest-util": "^29.7.0"
-            }
-        },
-        "jest-get-type": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
-            "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
-            "dev": true
-        },
-        "jest-haste-map": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
-            "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
-            "dev": true,
-            "requires": {
-                "@jest/types": "^29.6.3",
-                "@types/graceful-fs": "^4.1.3",
-                "@types/node": "*",
-                "anymatch": "^3.0.3",
-                "fb-watchman": "^2.0.0",
-                "fsevents": "^2.3.2",
-                "graceful-fs": "^4.2.9",
-                "jest-regex-util": "^29.6.3",
-                "jest-util": "^29.7.0",
-                "jest-worker": "^29.7.0",
-                "micromatch": "^4.0.4",
-                "walker": "^1.0.8"
-            },
-            "dependencies": {
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "jest-worker": {
-                    "version": "29.7.0",
-                    "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
-                    "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
-                    "dev": true,
-                    "requires": {
-                        "@types/node": "*",
-                        "jest-util": "^29.7.0",
-                        "merge-stream": "^2.0.0",
-                        "supports-color": "^8.0.0"
-                    }
-                },
-                "supports-color": {
-                    "version": "8.1.1",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-                    "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-leak-detector": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
-            "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
-            "dev": true,
-            "requires": {
-                "jest-get-type": "^29.6.3",
-                "pretty-format": "^29.7.0"
-            }
-        },
-        "jest-matcher-utils": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
-            "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
-            "dev": true,
-            "requires": {
-                "chalk": "^4.0.0",
-                "jest-diff": "^29.7.0",
-                "jest-get-type": "^29.6.3",
-                "pretty-format": "^29.7.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-message-util": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
-            "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
-            "dev": true,
-            "requires": {
-                "@babel/code-frame": "^7.12.13",
-                "@jest/types": "^29.6.3",
-                "@types/stack-utils": "^2.0.0",
-                "chalk": "^4.0.0",
-                "graceful-fs": "^4.2.9",
-                "micromatch": "^4.0.4",
-                "pretty-format": "^29.7.0",
-                "slash": "^3.0.0",
-                "stack-utils": "^2.0.3"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-mock": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
-            "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
-            "dev": true,
-            "requires": {
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "jest-util": "^29.7.0"
-            }
-        },
-        "jest-pnp-resolver": {
-            "version": "1.2.3",
-            "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
-            "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
-            "dev": true,
-            "requires": {}
-        },
-        "jest-regex-util": {
-            "version": "29.6.3",
-            "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
-            "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
-            "dev": true
-        },
-        "jest-resolve": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz",
-            "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
-            "dev": true,
-            "requires": {
-                "chalk": "^4.0.0",
-                "graceful-fs": "^4.2.9",
-                "jest-haste-map": "^29.7.0",
-                "jest-pnp-resolver": "^1.2.2",
-                "jest-util": "^29.7.0",
-                "jest-validate": "^29.7.0",
-                "resolve": "^1.20.0",
-                "resolve.exports": "^2.0.0",
-                "slash": "^3.0.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-resolve-dependencies": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
-            "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
-            "dev": true,
-            "requires": {
-                "jest-regex-util": "^29.6.3",
-                "jest-snapshot": "^29.7.0"
-            }
-        },
-        "jest-runner": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz",
-            "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
-            "dev": true,
-            "requires": {
-                "@jest/console": "^29.7.0",
-                "@jest/environment": "^29.7.0",
-                "@jest/test-result": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "emittery": "^0.13.1",
-                "graceful-fs": "^4.2.9",
-                "jest-docblock": "^29.7.0",
-                "jest-environment-node": "^29.7.0",
-                "jest-haste-map": "^29.7.0",
-                "jest-leak-detector": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-resolve": "^29.7.0",
-                "jest-runtime": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "jest-watcher": "^29.7.0",
-                "jest-worker": "^29.7.0",
-                "p-limit": "^3.1.0",
-                "source-map-support": "0.5.13"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "jest-worker": {
-                    "version": "29.7.0",
-                    "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
-                    "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
-                    "dev": true,
-                    "requires": {
-                        "@types/node": "*",
-                        "jest-util": "^29.7.0",
-                        "merge-stream": "^2.0.0",
-                        "supports-color": "^8.0.0"
-                    },
-                    "dependencies": {
-                        "supports-color": {
-                            "version": "8.1.1",
-                            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-                            "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
-                            "dev": true,
-                            "requires": {
-                                "has-flag": "^4.0.0"
-                            }
-                        }
-                    }
-                },
-                "source-map-support": {
-                    "version": "0.5.13",
-                    "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
-                    "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
-                    "dev": true,
-                    "requires": {
-                        "buffer-from": "^1.0.0",
-                        "source-map": "^0.6.0"
-                    }
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-runtime": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz",
-            "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
-            "dev": true,
-            "requires": {
-                "@jest/environment": "^29.7.0",
-                "@jest/fake-timers": "^29.7.0",
-                "@jest/globals": "^29.7.0",
-                "@jest/source-map": "^29.6.3",
-                "@jest/test-result": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "cjs-module-lexer": "^1.0.0",
-                "collect-v8-coverage": "^1.0.0",
-                "glob": "^7.1.3",
-                "graceful-fs": "^4.2.9",
-                "jest-haste-map": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-mock": "^29.7.0",
-                "jest-regex-util": "^29.6.3",
-                "jest-resolve": "^29.7.0",
-                "jest-snapshot": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "slash": "^3.0.0",
-                "strip-bom": "^4.0.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "strip-bom": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
-                    "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-snapshot": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
-            "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
-            "dev": true,
-            "requires": {
-                "@babel/core": "^7.11.6",
-                "@babel/generator": "^7.7.2",
-                "@babel/plugin-syntax-jsx": "^7.7.2",
-                "@babel/plugin-syntax-typescript": "^7.7.2",
-                "@babel/types": "^7.3.3",
-                "@jest/expect-utils": "^29.7.0",
-                "@jest/transform": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "babel-preset-current-node-syntax": "^1.0.0",
-                "chalk": "^4.0.0",
-                "expect": "^29.7.0",
-                "graceful-fs": "^4.2.9",
-                "jest-diff": "^29.7.0",
-                "jest-get-type": "^29.6.3",
-                "jest-matcher-utils": "^29.7.0",
-                "jest-message-util": "^29.7.0",
-                "jest-util": "^29.7.0",
-                "natural-compare": "^1.4.0",
-                "pretty-format": "^29.7.0",
-                "semver": "^7.5.3"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "lru-cache": {
-                    "version": "6.0.0",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-                    "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-                    "dev": true,
-                    "requires": {
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "semver": {
-                    "version": "7.6.0",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
-                    "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
-                    "dev": true,
-                    "requires": {
-                        "lru-cache": "^6.0.0"
-                    }
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                },
-                "yallist": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-                    "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-                    "dev": true
-                }
-            }
-        },
-        "jest-util": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
-            "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
-            "dev": true,
-            "requires": {
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "chalk": "^4.0.0",
-                "ci-info": "^3.2.0",
-                "graceful-fs": "^4.2.9",
-                "picomatch": "^2.2.3"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-validate": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz",
-            "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
-            "dev": true,
-            "requires": {
-                "@jest/types": "^29.6.3",
-                "camelcase": "^6.2.0",
-                "chalk": "^4.0.0",
-                "jest-get-type": "^29.6.3",
-                "leven": "^3.1.0",
-                "pretty-format": "^29.7.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "camelcase": {
-                    "version": "6.3.0",
-                    "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
-                    "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
-                    "dev": true
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-watcher": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz",
-            "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
-            "dev": true,
-            "requires": {
-                "@jest/test-result": "^29.7.0",
-                "@jest/types": "^29.6.3",
-                "@types/node": "*",
-                "ansi-escapes": "^4.2.1",
-                "chalk": "^4.0.0",
-                "emittery": "^0.13.1",
-                "jest-util": "^29.7.0",
-                "string-length": "^4.0.1"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jest-worker": {
-            "version": "27.5.1",
-            "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
-            "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
-            "dev": true,
-            "requires": {
-                "@types/node": "*",
-                "merge-stream": "^2.0.0",
-                "supports-color": "^8.0.0"
-            },
-            "dependencies": {
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "8.1.1",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
-                    "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
-            }
-        },
-        "jiti": {
-            "version": "1.19.3",
-            "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.19.3.tgz",
-            "integrity": "sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==",
-            "dev": true
-        },
-        "jquery": {
-            "version": "3.7.1",
-            "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
-            "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
-        },
-        "js-tokens": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-            "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
-        },
-        "js-yaml": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-            "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-            "dev": true,
-            "requires": {
-                "argparse": "^2.0.1"
-            }
-        },
-        "jsdom": {
-            "version": "20.0.3",
-            "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz",
-            "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==",
-            "dev": true,
-            "requires": {
-                "abab": "^2.0.6",
-                "acorn": "^8.8.1",
-                "acorn-globals": "^7.0.0",
-                "cssom": "^0.5.0",
-                "cssstyle": "^2.3.0",
-                "data-urls": "^3.0.2",
-                "decimal.js": "^10.4.2",
-                "domexception": "^4.0.0",
-                "escodegen": "^2.0.0",
-                "form-data": "^4.0.0",
-                "html-encoding-sniffer": "^3.0.0",
-                "http-proxy-agent": "^5.0.0",
-                "https-proxy-agent": "^5.0.1",
-                "is-potential-custom-element-name": "^1.0.1",
-                "nwsapi": "^2.2.2",
-                "parse5": "^7.1.1",
-                "saxes": "^6.0.0",
-                "symbol-tree": "^3.2.4",
-                "tough-cookie": "^4.1.2",
-                "w3c-xmlserializer": "^4.0.0",
-                "webidl-conversions": "^7.0.0",
-                "whatwg-encoding": "^2.0.0",
-                "whatwg-mimetype": "^3.0.0",
-                "whatwg-url": "^11.0.0",
-                "ws": "^8.11.0",
-                "xml-name-validator": "^4.0.0"
-            }
-        },
-        "jsesc": {
-            "version": "2.5.2",
-            "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
-            "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
-            "dev": true
-        },
-        "json-buffer": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
-            "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
-            "dev": true
-        },
-        "json-parse-even-better-errors": {
-            "version": "2.3.1",
-            "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
-            "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
-            "dev": true
-        },
-        "json-schema-traverse": {
-            "version": "0.4.1",
-            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-            "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-            "dev": true
-        },
-        "json-stable-stringify-without-jsonify": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-            "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
-            "dev": true
-        },
-        "json5": {
-            "version": "2.2.3",
-            "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
-            "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
-            "dev": true
-        },
-        "jsonfile": {
-            "version": "6.1.0",
-            "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
-            "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
-            "dev": true,
-            "requires": {
-                "graceful-fs": "^4.1.6",
-                "universalify": "^2.0.0"
-            }
-        },
-        "jsx-ast-utils": {
-            "version": "3.3.5",
-            "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
-            "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
-            "dev": true,
-            "requires": {
-                "array-includes": "^3.1.6",
-                "array.prototype.flat": "^1.3.1",
-                "object.assign": "^4.1.4",
-                "object.values": "^1.1.6"
-            }
-        },
-        "junk": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
-            "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==",
-            "dev": true
-        },
-        "keyv": {
-            "version": "4.5.3",
-            "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
-            "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==",
-            "dev": true,
-            "requires": {
-                "json-buffer": "3.0.1"
-            }
-        },
-        "kind-of": {
-            "version": "6.0.3",
-            "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
-            "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
-            "dev": true
-        },
-        "kleur": {
-            "version": "3.0.3",
-            "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
-            "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
-            "dev": true
-        },
-        "klona": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
-            "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
-            "dev": true
-        },
-        "laravel-echo": {
-            "version": "1.15.3",
-            "resolved": "https://registry.npmjs.org/laravel-echo/-/laravel-echo-1.15.3.tgz",
-            "integrity": "sha512-SRXzccaat6w4qKgZ4/rjFKr3nJfVxB+ly4V0MEJNIF1/TpERNXepo3uk7NnOjBGsiV/np1fl2XitAzW4Sa1s/w=="
-        },
-        "laravel-mix": {
-            "version": "6.0.49",
-            "resolved": "https://registry.npmjs.org/laravel-mix/-/laravel-mix-6.0.49.tgz",
-            "integrity": "sha512-bBMFpFjp26XfijPvY5y9zGKud7VqlyOE0OWUcPo3vTBY5asw8LTjafAbee1dhfLz6PWNqDziz69CP78ELSpfKw==",
-            "dev": true,
-            "requires": {
-                "@babel/core": "^7.15.8",
-                "@babel/plugin-proposal-object-rest-spread": "^7.15.6",
-                "@babel/plugin-syntax-dynamic-import": "^7.8.3",
-                "@babel/plugin-transform-runtime": "^7.15.8",
-                "@babel/preset-env": "^7.15.8",
-                "@babel/runtime": "^7.15.4",
-                "@types/babel__core": "^7.1.16",
-                "@types/clean-css": "^4.2.5",
-                "@types/imagemin-gifsicle": "^7.0.1",
-                "@types/imagemin-mozjpeg": "^8.0.1",
-                "@types/imagemin-optipng": "^5.2.1",
-                "@types/imagemin-svgo": "^8.0.0",
-                "autoprefixer": "^10.4.0",
-                "babel-loader": "^8.2.3",
-                "chalk": "^4.1.2",
-                "chokidar": "^3.5.2",
-                "clean-css": "^5.2.4",
-                "cli-table3": "^0.6.0",
-                "collect.js": "^4.28.5",
-                "commander": "^7.2.0",
-                "concat": "^1.0.3",
-                "css-loader": "^5.2.6",
-                "cssnano": "^5.0.8",
-                "dotenv": "^10.0.0",
-                "dotenv-expand": "^5.1.0",
-                "file-loader": "^6.2.0",
-                "fs-extra": "^10.0.0",
-                "glob": "^7.2.0",
-                "html-loader": "^1.3.2",
-                "imagemin": "^7.0.1",
-                "img-loader": "^4.0.0",
-                "lodash": "^4.17.21",
-                "md5": "^2.3.0",
-                "mini-css-extract-plugin": "^1.6.2",
-                "node-libs-browser": "^2.2.1",
-                "postcss-load-config": "^3.1.0",
-                "postcss-loader": "^6.2.0",
-                "semver": "^7.3.5",
-                "strip-ansi": "^6.0.0",
-                "style-loader": "^2.0.0",
-                "terser": "^5.9.0",
-                "terser-webpack-plugin": "^5.2.4",
-                "vue-style-loader": "^4.1.3",
-                "webpack": "^5.60.0",
-                "webpack-cli": "^4.9.1",
-                "webpack-dev-server": "^4.7.3",
-                "webpack-merge": "^5.8.0",
-                "webpack-notifier": "^1.14.1",
-                "webpackbar": "^5.0.0-3",
-                "yargs": "^17.2.1"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "lru-cache": {
-                    "version": "6.0.0",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-                    "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-                    "dev": true,
-                    "requires": {
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "semver": {
-                    "version": "7.5.4",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-                    "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
-                    "dev": true,
-                    "requires": {
-                        "lru-cache": "^6.0.0"
-                    }
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                },
-                "yallist": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-                    "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-                    "dev": true
-                }
-            }
-        },
-        "launch-editor": {
-            "version": "2.6.0",
-            "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz",
-            "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==",
-            "dev": true,
-            "requires": {
-                "picocolors": "^1.0.0",
-                "shell-quote": "^1.7.3"
-            }
-        },
-        "leven": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
-            "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
-            "dev": true
-        },
-        "levn": {
-            "version": "0.4.1",
-            "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
-            "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
-            "dev": true,
-            "requires": {
-                "prelude-ls": "^1.2.1",
-                "type-check": "~0.4.0"
-            }
-        },
-        "lie": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
-            "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==",
-            "requires": {
-                "immediate": "~3.0.5"
-            }
-        },
-        "lilconfig": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
-            "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
-            "dev": true
-        },
-        "lines-and-columns": {
-            "version": "1.2.4",
-            "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
-            "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
-            "dev": true
-        },
-        "loader-runner": {
-            "version": "4.3.0",
-            "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
-            "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
-            "dev": true
-        },
-        "loader-utils": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
-            "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
-            "dev": true,
-            "requires": {
-                "big.js": "^5.2.2",
-                "emojis-list": "^3.0.0",
-                "json5": "^2.1.2"
-            }
-        },
-        "localforage": {
-            "version": "1.10.0",
-            "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz",
-            "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==",
-            "requires": {
-                "lie": "3.1.1"
-            }
-        },
-        "locate-path": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-            "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-            "dev": true,
-            "requires": {
-                "p-locate": "^5.0.0"
-            }
-        },
-        "lodash": {
-            "version": "4.17.21",
-            "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-            "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
-        },
-        "lodash-es": {
-            "version": "4.17.21",
-            "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
-            "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
-        },
-        "lodash.debounce": {
-            "version": "4.0.8",
-            "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
-            "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
-            "dev": true
-        },
-        "lodash.memoize": {
-            "version": "4.1.2",
-            "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
-            "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
-            "dev": true
-        },
-        "lodash.merge": {
-            "version": "4.6.2",
-            "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-            "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-            "dev": true
-        },
-        "lodash.uniq": {
-            "version": "4.5.0",
-            "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
-            "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
-            "dev": true
-        },
-        "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==",
-            "requires": {
-                "js-tokens": "^3.0.0 || ^4.0.0"
-            }
-        },
-        "lower-case": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
-            "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
-            "dev": true,
-            "requires": {
-                "tslib": "^2.0.3"
-            }
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "yallist": "^3.0.2"
-            }
-        },
-        "lz-string": {
-            "version": "1.5.0",
-            "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
-            "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
-            "dev": true
-        },
-        "make-dir": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-            "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-            "dev": true,
-            "requires": {
-                "semver": "^6.0.0"
-            }
-        },
-        "makeerror": {
-            "version": "1.0.12",
-            "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
-            "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
-            "dev": true,
-            "requires": {
-                "tmpl": "1.0.5"
-            }
-        },
-        "md5": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
-            "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
-            "dev": true,
-            "requires": {
-                "charenc": "0.0.2",
-                "crypt": "0.0.2",
-                "is-buffer": "~1.1.6"
-            }
-        },
-        "md5.js": {
-            "version": "1.3.5",
-            "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
-            "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
-            "dev": true,
-            "requires": {
-                "hash-base": "^3.0.0",
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.1.2"
-            }
-        },
-        "mdn-data": {
-            "version": "2.0.14",
-            "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
-            "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
-            "dev": true
-        },
-        "media-typer": {
-            "version": "0.3.0",
-            "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
-            "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
-            "dev": true
-        },
-        "memfs": {
-            "version": "3.5.3",
-            "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz",
-            "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==",
-            "dev": true,
-            "requires": {
-                "fs-monkey": "^1.0.4"
-            }
-        },
-        "merge-descriptors": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-            "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
-            "dev": true
-        },
-        "merge-stream": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
-            "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
-            "dev": true
-        },
-        "merge2": {
-            "version": "1.4.1",
-            "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
-            "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
-            "dev": true
-        },
-        "methods": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
-            "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
-            "dev": true
-        },
-        "micromatch": {
-            "version": "4.0.5",
-            "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
-            "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
-            "dev": true,
-            "requires": {
-                "braces": "^3.0.2",
-                "picomatch": "^2.3.1"
-            }
-        },
-        "miller-rabin": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
-            "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
-            "dev": true,
-            "requires": {
-                "bn.js": "^4.0.0",
-                "brorand": "^1.0.1"
-            },
-            "dependencies": {
-                "bn.js": {
-                    "version": "4.12.0",
-                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-                    "dev": true
-                }
-            }
-        },
-        "mime": {
-            "version": "1.6.0",
-            "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-            "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
-            "dev": true
-        },
-        "mime-db": {
-            "version": "1.52.0",
-            "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
-            "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
-            "dev": true
-        },
-        "mime-types": {
-            "version": "2.1.35",
-            "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
-            "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-            "dev": true,
-            "requires": {
-                "mime-db": "1.52.0"
-            }
-        },
-        "mimic-fn": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
-            "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
-            "dev": true
-        },
-        "min-indent": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
-            "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
-            "dev": true
-        },
-        "mini-css-extract-plugin": {
-            "version": "1.6.2",
-            "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz",
-            "integrity": "sha512-WhDvO3SjGm40oV5y26GjMJYjd2UMqrLAGKy5YS2/3QKJy2F7jgynuHTir/tgUUOiNQu5saXHdc8reo7YuhhT4Q==",
-            "dev": true,
-            "requires": {
-                "loader-utils": "^2.0.0",
-                "schema-utils": "^3.0.0",
-                "webpack-sources": "^1.1.0"
-            },
-            "dependencies": {
-                "schema-utils": {
-                    "version": "3.3.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-                    "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.8",
-                        "ajv": "^6.12.5",
-                        "ajv-keywords": "^3.5.2"
-                    }
-                }
-            }
-        },
-        "mini-svg-data-uri": {
-            "version": "1.4.4",
-            "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
-            "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
-            "dev": true
-        },
-        "minimalistic-assert": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
-            "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
-            "dev": true
-        },
-        "minimalistic-crypto-utils": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
-            "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==",
-            "dev": true
-        },
-        "minimatch": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-            "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-            "dev": true,
-            "requires": {
-                "brace-expansion": "^1.1.7"
-            }
-        },
-        "minimist": {
-            "version": "1.2.8",
-            "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
-            "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
-            "dev": true
-        },
-        "moment": {
-            "version": "2.29.4",
-            "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
-            "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
-        },
-        "ms": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-            "dev": true
-        },
-        "multicast-dns": {
-            "version": "7.2.5",
-            "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",
-            "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==",
-            "dev": true,
-            "requires": {
-                "dns-packet": "^5.2.2",
-                "thunky": "^1.0.2"
-            }
-        },
-        "mz": {
-            "version": "2.7.0",
-            "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
-            "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
-            "dev": true,
-            "requires": {
-                "any-promise": "^1.0.0",
-                "object-assign": "^4.0.1",
-                "thenify-all": "^1.0.0"
-            }
-        },
-        "nanoid": {
-            "version": "3.3.6",
-            "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
-            "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
-            "dev": true
-        },
-        "natural-compare": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-            "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
-            "dev": true
-        },
-        "negotiator": {
-            "version": "0.6.3",
-            "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
-            "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
-            "dev": true
-        },
-        "neo-async": {
-            "version": "2.6.2",
-            "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
-            "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
-            "dev": true
-        },
-        "no-case": {
-            "version": "3.0.4",
-            "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
-            "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
-            "dev": true,
-            "requires": {
-                "lower-case": "^2.0.2",
-                "tslib": "^2.0.3"
-            }
-        },
-        "node-forge": {
-            "version": "1.3.1",
-            "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
-            "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
-            "dev": true
-        },
-        "node-int64": {
-            "version": "0.4.0",
-            "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
-            "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
-            "dev": true
-        },
-        "node-libs-browser": {
-            "version": "2.2.1",
-            "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
-            "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
-            "dev": true,
-            "requires": {
-                "assert": "^1.1.1",
-                "browserify-zlib": "^0.2.0",
-                "buffer": "^4.3.0",
-                "console-browserify": "^1.1.0",
-                "constants-browserify": "^1.0.0",
-                "crypto-browserify": "^3.11.0",
-                "domain-browser": "^1.1.1",
-                "events": "^3.0.0",
-                "https-browserify": "^1.0.0",
-                "os-browserify": "^0.3.0",
-                "path-browserify": "0.0.1",
-                "process": "^0.11.10",
-                "punycode": "^1.2.4",
-                "querystring-es3": "^0.2.0",
-                "readable-stream": "^2.3.3",
-                "stream-browserify": "^2.0.1",
-                "stream-http": "^2.7.2",
-                "string_decoder": "^1.0.0",
-                "timers-browserify": "^2.0.4",
-                "tty-browserify": "0.0.0",
-                "url": "^0.11.0",
-                "util": "^0.11.0",
-                "vm-browserify": "^1.0.1"
-            }
-        },
-        "node-notifier": {
-            "version": "9.0.1",
-            "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-9.0.1.tgz",
-            "integrity": "sha512-fPNFIp2hF/Dq7qLDzSg4vZ0J4e9v60gJR+Qx7RbjbWqzPDdEqeVpEx5CFeDAELIl+A/woaaNn1fQ5nEVerMxJg==",
-            "dev": true,
-            "requires": {
-                "growly": "^1.3.0",
-                "is-wsl": "^2.2.0",
-                "semver": "^7.3.2",
-                "shellwords": "^0.1.1",
-                "uuid": "^8.3.0",
-                "which": "^2.0.2"
-            },
-            "dependencies": {
-                "lru-cache": {
-                    "version": "6.0.0",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-                    "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-                    "dev": true,
-                    "requires": {
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "semver": {
-                    "version": "7.5.4",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-                    "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
-                    "dev": true,
-                    "requires": {
-                        "lru-cache": "^6.0.0"
-                    }
-                },
-                "yallist": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-                    "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-                    "dev": true
-                }
-            }
-        },
-        "node-releases": {
-            "version": "2.0.14",
-            "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz",
-            "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==",
-            "dev": true
-        },
-        "normalize-path": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-            "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-            "dev": true
-        },
-        "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
-        },
-        "normalize-url": {
-            "version": "6.1.0",
-            "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
-            "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
-            "dev": true
-        },
-        "npm-run-path": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-            "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
-            "dev": true,
-            "requires": {
-                "path-key": "^3.0.0"
-            }
-        },
-        "nth-check": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
-            "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
-            "dev": true,
-            "requires": {
-                "boolbase": "^1.0.0"
-            }
-        },
-        "numeral": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz",
-            "integrity": "sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA=="
-        },
-        "nwsapi": {
-            "version": "2.2.7",
-            "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz",
-            "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==",
-            "dev": true
-        },
-        "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=="
-        },
-        "object-hash": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
-            "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
-            "dev": true
-        },
-        "object-inspect": {
-            "version": "1.12.3",
-            "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
-            "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
-        },
-        "object-is": {
-            "version": "1.1.5",
-            "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
-            "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.3"
-            }
-        },
-        "object-keys": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-            "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-            "dev": true
-        },
-        "object.assign": {
-            "version": "4.1.4",
-            "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
-            "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "has-symbols": "^1.0.3",
-                "object-keys": "^1.1.1"
-            }
-        },
-        "object.entries": {
-            "version": "1.1.7",
-            "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz",
-            "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            }
-        },
-        "object.fromentries": {
-            "version": "2.0.7",
-            "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz",
-            "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            }
-        },
-        "object.groupby": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz",
-            "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1"
-            }
-        },
-        "object.hasown": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz",
-            "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==",
-            "dev": true,
-            "requires": {
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            }
-        },
-        "object.values": {
-            "version": "1.1.7",
-            "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz",
-            "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            }
-        },
-        "obuf": {
-            "version": "1.1.2",
-            "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
-            "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
-            "dev": true
-        },
-        "on-finished": {
-            "version": "2.4.1",
-            "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
-            "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
-            "dev": true,
-            "requires": {
-                "ee-first": "1.1.1"
-            }
-        },
-        "on-headers": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
-            "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
-            "dev": true
-        },
-        "once": {
-            "version": "1.4.0",
-            "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-            "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-            "dev": true,
-            "requires": {
-                "wrappy": "1"
-            }
-        },
-        "onetime": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
-            "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
-            "dev": true,
-            "requires": {
-                "mimic-fn": "^2.1.0"
-            }
-        },
-        "open": {
-            "version": "8.4.2",
-            "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
-            "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
-            "dev": true,
-            "requires": {
-                "define-lazy-prop": "^2.0.0",
-                "is-docker": "^2.1.1",
-                "is-wsl": "^2.2.0"
-            }
-        },
-        "openseadragon": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/openseadragon/-/openseadragon-4.1.0.tgz",
-            "integrity": "sha512-XMMzf5apmshvIvxvqMwiW9dJ07dol4zudvV1oFnoZuIpSZP3c3tlFjGbyOKHGhb1k4jmHQ7b7koG9vCHdKvC/A=="
-        },
-        "optionator": {
-            "version": "0.9.3",
-            "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
-            "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
-            "dev": true,
-            "requires": {
-                "@aashutoshrathi/word-wrap": "^1.2.3",
-                "deep-is": "^0.1.3",
-                "fast-levenshtein": "^2.0.6",
-                "levn": "^0.4.1",
-                "prelude-ls": "^1.2.1",
-                "type-check": "^0.4.0"
-            }
-        },
-        "os-browserify": {
-            "version": "0.3.0",
-            "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
-            "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==",
-            "dev": true
-        },
-        "p-limit": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-            "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-            "dev": true,
-            "requires": {
-                "yocto-queue": "^0.1.0"
-            }
-        },
-        "p-locate": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-            "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-            "dev": true,
-            "requires": {
-                "p-limit": "^3.0.2"
-            }
-        },
-        "p-pipe": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/p-pipe/-/p-pipe-3.1.0.tgz",
-            "integrity": "sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw==",
-            "dev": true
-        },
-        "p-retry": {
-            "version": "4.6.2",
-            "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
-            "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
-            "dev": true,
-            "requires": {
-                "@types/retry": "0.12.0",
-                "retry": "^0.13.1"
-            }
-        },
-        "p-try": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-            "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-            "dev": true
-        },
-        "pako": {
-            "version": "1.0.11",
-            "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
-            "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
-            "dev": true
-        },
-        "param-case": {
-            "version": "3.0.4",
-            "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
-            "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
-            "dev": true,
-            "requires": {
-                "dot-case": "^3.0.4",
-                "tslib": "^2.0.3"
-            }
-        },
-        "parent-module": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-            "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-            "dev": true,
-            "requires": {
-                "callsites": "^3.0.0"
-            }
-        },
-        "parse-asn1": {
-            "version": "5.1.6",
-            "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
-            "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
-            "dev": true,
-            "requires": {
-                "asn1.js": "^5.2.0",
-                "browserify-aes": "^1.0.0",
-                "evp_bytestokey": "^1.0.0",
-                "pbkdf2": "^3.0.3",
-                "safe-buffer": "^5.1.1"
-            }
-        },
-        "parse-json": {
-            "version": "5.2.0",
-            "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
-            "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
-            "dev": true,
-            "requires": {
-                "@babel/code-frame": "^7.0.0",
-                "error-ex": "^1.3.1",
-                "json-parse-even-better-errors": "^2.3.0",
-                "lines-and-columns": "^1.1.6"
-            }
-        },
-        "parse5": {
-            "version": "7.1.2",
-            "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
-            "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
-            "dev": true,
-            "requires": {
-                "entities": "^4.4.0"
-            },
-            "dependencies": {
-                "entities": {
-                    "version": "4.5.0",
-                    "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
-                    "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
-                    "dev": true
-                }
-            }
-        },
-        "parseurl": {
-            "version": "1.3.3",
-            "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
-            "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
-            "dev": true
-        },
-        "pascal-case": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
-            "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
-            "dev": true,
-            "requires": {
-                "no-case": "^3.0.4",
-                "tslib": "^2.0.3"
-            }
-        },
-        "path-browserify": {
-            "version": "0.0.1",
-            "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
-            "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
-            "dev": true
-        },
-        "path-exists": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-            "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-            "dev": true
-        },
-        "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==",
-            "dev": true
-        },
-        "path-key": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-            "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-            "dev": true
-        },
-        "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==",
-            "dev": true
-        },
-        "path-to-regexp": {
-            "version": "0.1.7",
-            "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-            "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
-            "dev": true
-        },
-        "path-type": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-            "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
-            "dev": true
-        },
-        "pbkdf2": {
-            "version": "3.1.2",
-            "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
-            "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
-            "dev": true,
-            "requires": {
-                "create-hash": "^1.1.2",
-                "create-hmac": "^1.1.4",
-                "ripemd160": "^2.0.1",
-                "safe-buffer": "^5.0.1",
-                "sha.js": "^2.4.8"
-            }
-        },
-        "picocolors": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-            "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
-            "dev": true
-        },
-        "picomatch": {
-            "version": "2.3.1",
-            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-            "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-            "dev": true
-        },
-        "pify": {
-            "version": "2.3.0",
-            "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-            "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
-            "dev": true
-        },
-        "pirates": {
-            "version": "4.0.6",
-            "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
-            "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
-            "dev": true
-        },
-        "pkg-dir": {
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-            "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
-            "dev": true,
-            "requires": {
-                "find-up": "^4.0.0"
-            },
-            "dependencies": {
-                "find-up": {
-                    "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-                    "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-                    "dev": true,
-                    "requires": {
-                        "locate-path": "^5.0.0",
-                        "path-exists": "^4.0.0"
-                    }
-                },
-                "locate-path": {
-                    "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-                    "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-                    "dev": true,
-                    "requires": {
-                        "p-locate": "^4.1.0"
-                    }
-                },
-                "p-limit": {
-                    "version": "2.3.0",
-                    "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-                    "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-                    "dev": true,
-                    "requires": {
-                        "p-try": "^2.0.0"
-                    }
-                },
-                "p-locate": {
-                    "version": "4.1.0",
-                    "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-                    "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-                    "dev": true,
-                    "requires": {
-                        "p-limit": "^2.2.0"
-                    }
-                }
-            }
-        },
-        "possible-typed-array-names": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
-            "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
-            "dev": true
-        },
-        "postcss": {
-            "version": "8.4.29",
-            "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
-            "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==",
-            "dev": true,
-            "requires": {
-                "nanoid": "^3.3.6",
-                "picocolors": "^1.0.0",
-                "source-map-js": "^1.0.2"
-            }
-        },
-        "postcss-calc": {
-            "version": "8.2.4",
-            "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz",
-            "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==",
-            "dev": true,
-            "requires": {
-                "postcss-selector-parser": "^6.0.9",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-colormin": {
-            "version": "5.3.1",
-            "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz",
-            "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.21.4",
-                "caniuse-api": "^3.0.0",
-                "colord": "^2.9.1",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-convert-values": {
-            "version": "5.1.3",
-            "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz",
-            "integrity": "sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.21.4",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-discard-comments": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz",
-            "integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==",
-            "dev": true,
-            "requires": {}
-        },
-        "postcss-discard-duplicates": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz",
-            "integrity": "sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==",
-            "dev": true,
-            "requires": {}
-        },
-        "postcss-discard-empty": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz",
-            "integrity": "sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==",
-            "dev": true,
-            "requires": {}
-        },
-        "postcss-discard-overridden": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz",
-            "integrity": "sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==",
-            "dev": true,
-            "requires": {}
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.0.0",
-                "read-cache": "^1.0.0",
-                "resolve": "^1.1.7"
-            }
-        },
-        "postcss-js": {
-            "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
-            "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
-            "dev": true,
-            "requires": {
-                "camelcase-css": "^2.0.1"
-            }
-        },
-        "postcss-load-config": {
-            "version": "3.1.4",
-            "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
-            "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
-            "dev": true,
-            "requires": {
-                "lilconfig": "^2.0.5",
-                "yaml": "^1.10.2"
-            }
-        },
-        "postcss-loader": {
-            "version": "6.2.1",
-            "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz",
-            "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==",
-            "dev": true,
-            "requires": {
-                "cosmiconfig": "^7.0.0",
-                "klona": "^2.0.5",
-                "semver": "^7.3.5"
-            },
-            "dependencies": {
-                "lru-cache": {
-                    "version": "6.0.0",
-                    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
-                    "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
-                    "dev": true,
-                    "requires": {
-                        "yallist": "^4.0.0"
-                    }
-                },
-                "semver": {
-                    "version": "7.5.4",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
-                    "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
-                    "dev": true,
-                    "requires": {
-                        "lru-cache": "^6.0.0"
-                    }
-                },
-                "yallist": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
-                    "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
-                    "dev": true
-                }
-            }
-        },
-        "postcss-merge-longhand": {
-            "version": "5.1.7",
-            "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz",
-            "integrity": "sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0",
-                "stylehacks": "^5.1.1"
-            }
-        },
-        "postcss-merge-rules": {
-            "version": "5.1.4",
-            "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz",
-            "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.21.4",
-                "caniuse-api": "^3.0.0",
-                "cssnano-utils": "^3.1.0",
-                "postcss-selector-parser": "^6.0.5"
-            }
-        },
-        "postcss-minify-font-values": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz",
-            "integrity": "sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-minify-gradients": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz",
-            "integrity": "sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==",
-            "dev": true,
-            "requires": {
-                "colord": "^2.9.1",
-                "cssnano-utils": "^3.1.0",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-minify-params": {
-            "version": "5.1.4",
-            "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz",
-            "integrity": "sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.21.4",
-                "cssnano-utils": "^3.1.0",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-minify-selectors": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz",
-            "integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==",
-            "dev": true,
-            "requires": {
-                "postcss-selector-parser": "^6.0.5"
-            }
-        },
-        "postcss-modules-extract-imports": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
-            "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
-            "dev": true,
-            "requires": {}
-        },
-        "postcss-modules-local-by-default": {
-            "version": "4.0.3",
-            "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz",
-            "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==",
-            "dev": true,
-            "requires": {
-                "icss-utils": "^5.0.0",
-                "postcss-selector-parser": "^6.0.2",
-                "postcss-value-parser": "^4.1.0"
-            }
-        },
-        "postcss-modules-scope": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
-            "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
-            "dev": true,
-            "requires": {
-                "postcss-selector-parser": "^6.0.4"
-            }
-        },
-        "postcss-modules-values": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
-            "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
-            "dev": true,
-            "requires": {
-                "icss-utils": "^5.0.0"
-            }
-        },
-        "postcss-nested": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
-            "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
-            "dev": true,
-            "requires": {
-                "postcss-selector-parser": "^6.0.11"
-            }
-        },
-        "postcss-normalize-charset": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz",
-            "integrity": "sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==",
-            "dev": true,
-            "requires": {}
-        },
-        "postcss-normalize-display-values": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz",
-            "integrity": "sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-normalize-positions": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz",
-            "integrity": "sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-normalize-repeat-style": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz",
-            "integrity": "sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-normalize-string": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz",
-            "integrity": "sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-normalize-timing-functions": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz",
-            "integrity": "sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-normalize-unicode": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz",
-            "integrity": "sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.21.4",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-normalize-url": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz",
-            "integrity": "sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==",
-            "dev": true,
-            "requires": {
-                "normalize-url": "^6.0.1",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-normalize-whitespace": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz",
-            "integrity": "sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-ordered-values": {
-            "version": "5.1.3",
-            "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz",
-            "integrity": "sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==",
-            "dev": true,
-            "requires": {
-                "cssnano-utils": "^3.1.0",
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "postcss-reduce-initial": {
-            "version": "5.1.2",
-            "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz",
-            "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==",
-            "dev": true,
-            "requires": {
-                "browserslist": "^4.21.4",
-                "caniuse-api": "^3.0.0"
-            }
-        },
-        "postcss-reduce-transforms": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz",
-            "integrity": "sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0"
-            }
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "cssesc": "^3.0.0",
-                "util-deprecate": "^1.0.2"
-            }
-        },
-        "postcss-svgo": {
-            "version": "5.1.0",
-            "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.1.0.tgz",
-            "integrity": "sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==",
-            "dev": true,
-            "requires": {
-                "postcss-value-parser": "^4.2.0",
-                "svgo": "^2.7.0"
-            }
-        },
-        "postcss-unique-selectors": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz",
-            "integrity": "sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==",
-            "dev": true,
-            "requires": {
-                "postcss-selector-parser": "^6.0.5"
-            }
-        },
-        "postcss-value-parser": {
-            "version": "4.2.0",
-            "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
-            "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
-            "dev": true
-        },
-        "prelude-ls": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-            "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
-            "dev": true
-        },
-        "pretty-format": {
-            "version": "29.7.0",
-            "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
-            "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
-            "dev": true,
-            "requires": {
-                "@jest/schemas": "^29.6.3",
-                "ansi-styles": "^5.0.0",
-                "react-is": "^18.0.0"
-            },
-            "dependencies": {
-                "ansi-styles": {
-                    "version": "5.2.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
-                    "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
-                    "dev": true
-                },
-                "react-is": {
-                    "version": "18.2.0",
-                    "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
-                    "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
-                    "dev": true
-                }
-            }
-        },
-        "pretty-time": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz",
-            "integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==",
-            "dev": true
-        },
-        "process": {
-            "version": "0.11.10",
-            "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
-            "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
-            "dev": true
-        },
-        "process-nextick-args": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-            "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
-            "dev": true
-        },
-        "prompts": {
-            "version": "2.4.2",
-            "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
-            "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
-            "dev": true,
-            "requires": {
-                "kleur": "^3.0.3",
-                "sisteransi": "^1.0.5"
-            }
-        },
-        "prop-types": {
-            "version": "15.8.1",
-            "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
-            "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
-            "requires": {
-                "loose-envify": "^1.4.0",
-                "object-assign": "^4.1.1",
-                "react-is": "^16.13.1"
-            }
-        },
-        "prop-types-extra": {
-            "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
-            "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
-            "requires": {
-                "react-is": "^16.3.2",
-                "warning": "^4.0.0"
-            }
-        },
-        "property-expr": {
-            "version": "2.0.5",
-            "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
-            "integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
-        },
-        "proxy-addr": {
-            "version": "2.0.7",
-            "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
-            "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
-            "dev": true,
-            "requires": {
-                "forwarded": "0.2.0",
-                "ipaddr.js": "1.9.1"
-            },
-            "dependencies": {
-                "ipaddr.js": {
-                    "version": "1.9.1",
-                    "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
-                    "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
-                    "dev": true
-                }
-            }
-        },
-        "proxy-from-env": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
-            "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
-            "dev": true
-        },
-        "psl": {
-            "version": "1.9.0",
-            "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
-            "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
-            "dev": true
-        },
-        "public-encrypt": {
-            "version": "4.0.3",
-            "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
-            "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
-            "dev": true,
-            "requires": {
-                "bn.js": "^4.1.0",
-                "browserify-rsa": "^4.0.0",
-                "create-hash": "^1.1.0",
-                "parse-asn1": "^5.0.0",
-                "randombytes": "^2.0.1",
-                "safe-buffer": "^5.1.2"
-            },
-            "dependencies": {
-                "bn.js": {
-                    "version": "4.12.0",
-                    "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
-                    "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
-                    "dev": true
-                }
-            }
-        },
-        "punycode": {
-            "version": "1.4.1",
-            "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-            "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
-            "dev": true
-        },
-        "pure-rand": {
-            "version": "6.0.4",
-            "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz",
-            "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==",
-            "dev": true
-        },
-        "pusher-js": {
-            "version": "8.3.0",
-            "resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-8.3.0.tgz",
-            "integrity": "sha512-6GohP06WlVeomAQQe9qWh1IDzd3+InluWt+ZUOcecVK1SEQkg6a8uYVsvxSJm7cbccfmHhE0jDkmhKIhue8vmA==",
-            "requires": {
-                "tweetnacl": "^1.0.3"
-            }
-        },
-        "qs": {
-            "version": "6.11.2",
-            "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
-            "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
-            "requires": {
-                "side-channel": "^1.0.4"
-            }
-        },
-        "querystring-es3": {
-            "version": "0.2.1",
-            "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
-            "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==",
-            "dev": true
-        },
-        "querystringify": {
-            "version": "2.2.0",
-            "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-            "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
-            "dev": true
-        },
-        "queue-microtask": {
-            "version": "1.2.3",
-            "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
-            "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-            "dev": true
-        },
-        "randombytes": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
-            "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
-            "dev": true,
-            "requires": {
-                "safe-buffer": "^5.1.0"
-            }
-        },
-        "randomfill": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
-            "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
-            "dev": true,
-            "requires": {
-                "randombytes": "^2.0.5",
-                "safe-buffer": "^5.1.0"
-            }
-        },
-        "range-parser": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-            "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
-            "dev": true
-        },
-        "raw-body": {
-            "version": "2.5.1",
-            "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
-            "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
-            "dev": true,
-            "requires": {
-                "bytes": "3.1.2",
-                "http-errors": "2.0.0",
-                "iconv-lite": "0.4.24",
-                "unpipe": "1.0.0"
-            },
-            "dependencies": {
-                "bytes": {
-                    "version": "3.1.2",
-                    "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
-                    "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
-                    "dev": true
-                }
-            }
-        },
-        "react": {
-            "version": "18.2.0",
-            "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
-            "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
-            "requires": {
-                "loose-envify": "^1.1.0"
-            }
-        },
-        "react-bootstrap": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.8.0.tgz",
-            "integrity": "sha512-e/aNtxl0Z2ozrIaR82jr6Zz7ss9GSoaXpQaxmvtDUsTZIq/XalkduR/ZXP6vbQHz2T4syvjA+4FbtwELxxmpww==",
-            "requires": {
-                "@babel/runtime": "^7.21.0",
-                "@restart/hooks": "^0.4.9",
-                "@restart/ui": "^1.6.3",
-                "@types/react-transition-group": "^4.4.5",
-                "classnames": "^2.3.2",
-                "dom-helpers": "^5.2.1",
-                "invariant": "^2.2.4",
-                "prop-types": "^15.8.1",
-                "prop-types-extra": "^1.1.0",
-                "react-transition-group": "^4.4.5",
-                "uncontrollable": "^7.2.1",
-                "warning": "^4.0.3"
-            }
-        },
-        "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==",
-            "requires": {
-                "loose-envify": "^1.1.0",
-                "scheduler": "^0.23.0"
-            }
-        },
-        "react-fast-compare": {
-            "version": "2.0.4",
-            "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
-            "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
-        },
-        "react-helmet": {
-            "version": "6.1.0",
-            "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz",
-            "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==",
-            "requires": {
-                "object-assign": "^4.1.1",
-                "prop-types": "^15.7.2",
-                "react-fast-compare": "^3.1.1",
-                "react-side-effect": "^2.1.0"
-            },
-            "dependencies": {
-                "react-fast-compare": {
-                    "version": "3.2.2",
-                    "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
-                    "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
-                }
-            }
-        },
-        "react-i18next": {
-            "version": "13.2.2",
-            "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-13.2.2.tgz",
-            "integrity": "sha512-+nFUkbRByFwnrfDcYqvzBuaeZb+nACHx+fAWN/pZMddWOCJH5hoc21+Sa/N/Lqi6ne6/9wC/qRGOoQhJa6IkEQ==",
-            "requires": {
-                "@babel/runtime": "^7.22.5",
-                "html-parse-stringify": "^3.0.1"
-            }
-        },
-        "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=="
-        },
-        "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=="
-        },
-        "react-resize-detector": {
-            "version": "8.1.0",
-            "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-8.1.0.tgz",
-            "integrity": "sha512-S7szxlaIuiy5UqLhLL1KY3aoyGHbZzsTpYal9eYMwCyKqoqoVLCmIgAgNyIM1FhnP2KyBygASJxdhejrzjMb+w==",
-            "requires": {
-                "lodash": "^4.17.21"
-            }
-        },
-        "react-router": {
-            "version": "6.15.0",
-            "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.15.0.tgz",
-            "integrity": "sha512-NIytlzvzLwJkCQj2HLefmeakxxWHWAP+02EGqWEZy+DgfHHKQMUoBBjUQLOtFInBMhWtb3hiUy6MfFgwLjXhqg==",
-            "requires": {
-                "@remix-run/router": "1.8.0"
-            }
-        },
-        "react-router-bootstrap": {
-            "version": "0.26.2",
-            "resolved": "https://registry.npmjs.org/react-router-bootstrap/-/react-router-bootstrap-0.26.2.tgz",
-            "integrity": "sha512-YlpI9Xi+Uqp6zFAUO8D/wu6P8mr1ujqq+0V5MhJG1kx9dr/95fAMoGk4J+/CsysOkwtR3tYSac4DDWmHwXvC8w==",
-            "requires": {
-                "prop-types": "^15.7.2"
-            }
-        },
-        "react-router-dom": {
-            "version": "6.15.0",
-            "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.15.0.tgz",
-            "integrity": "sha512-aR42t0fs7brintwBGAv2+mGlCtgtFQeOzK0BM1/OiqEzRejOZtpMZepvgkscpMUnKb8YO84G7s3LsHnnDNonbQ==",
-            "requires": {
-                "@remix-run/router": "1.8.0",
-                "react-router": "6.15.0"
-            }
-        },
-        "react-side-effect": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz",
-            "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==",
-            "requires": {}
-        },
-        "react-smooth": {
-            "version": "2.0.3",
-            "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.3.tgz",
-            "integrity": "sha512-yl4y3XiMorss7ayF5QnBiSprig0+qFHui8uh7Hgg46QX5O+aRMRKlfGGNGLHno35JkQSvSYY8eCWkBfHfrSHfg==",
-            "requires": {
-                "fast-equals": "^5.0.0",
-                "react-transition-group": "2.9.0"
-            },
-            "dependencies": {
-                "dom-helpers": {
-                    "version": "3.4.0",
-                    "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
-                    "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
-                    "requires": {
-                        "@babel/runtime": "^7.1.2"
-                    }
-                },
-                "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==",
-                    "requires": {
-                        "dom-helpers": "^3.4.0",
-                        "loose-envify": "^1.4.0",
-                        "prop-types": "^15.6.2",
-                        "react-lifecycles-compat": "^3.0.4"
-                    }
-                }
-            }
-        },
-        "react-transition-group": {
-            "version": "4.4.5",
-            "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
-            "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
-            "requires": {
-                "@babel/runtime": "^7.5.5",
-                "dom-helpers": "^5.0.1",
-                "loose-envify": "^1.4.0",
-                "prop-types": "^15.6.2"
-            }
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "pify": "^2.3.0"
-            }
-        },
-        "readable-stream": {
-            "version": "2.3.8",
-            "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
-            "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
-            "dev": true,
-            "requires": {
-                "core-util-is": "~1.0.0",
-                "inherits": "~2.0.3",
-                "isarray": "~1.0.0",
-                "process-nextick-args": "~2.0.0",
-                "safe-buffer": "~5.1.1",
-                "string_decoder": "~1.1.1",
-                "util-deprecate": "~1.0.1"
-            },
-            "dependencies": {
-                "safe-buffer": {
-                    "version": "5.1.2",
-                    "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-                    "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-                    "dev": true
-                },
-                "string_decoder": {
-                    "version": "1.1.1",
-                    "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-                    "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-                    "dev": true,
-                    "requires": {
-                        "safe-buffer": "~5.1.0"
-                    }
-                }
-            }
-        },
-        "readdirp": {
-            "version": "3.6.0",
-            "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-            "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-            "dev": true,
-            "requires": {
-                "picomatch": "^2.2.1"
-            }
-        },
-        "recharts": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.8.0.tgz",
-            "integrity": "sha512-nciXqQDh3aW8abhwUlA4EBOBusRHLNiKHfpRZiG/yjups1x+auHb2zWPuEcTn/IMiN47vVMMuF8Sr+vcQJtsmw==",
-            "requires": {
-                "classnames": "^2.2.5",
-                "eventemitter3": "^4.0.1",
-                "lodash": "^4.17.19",
-                "react-is": "^16.10.2",
-                "react-resize-detector": "^8.0.4",
-                "react-smooth": "^2.0.2",
-                "recharts-scale": "^0.4.4",
-                "reduce-css-calc": "^2.1.8",
-                "victory-vendor": "^36.6.8"
-            }
-        },
-        "recharts-scale": {
-            "version": "0.4.5",
-            "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
-            "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
-            "requires": {
-                "decimal.js-light": "^2.4.1"
-            }
-        },
-        "rechoir": {
-            "version": "0.7.1",
-            "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
-            "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
-            "dev": true,
-            "requires": {
-                "resolve": "^1.9.0"
-            }
-        },
-        "redent": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
-            "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
-            "dev": true,
-            "requires": {
-                "indent-string": "^4.0.0",
-                "strip-indent": "^3.0.0"
-            }
-        },
-        "reduce-css-calc": {
-            "version": "2.1.8",
-            "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
-            "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
-            "requires": {
-                "css-unit-converter": "^1.1.1",
-                "postcss-value-parser": "^3.3.0"
-            },
-            "dependencies": {
-                "postcss-value-parser": {
-                    "version": "3.3.1",
-                    "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-                    "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
-                }
-            }
-        },
-        "reflect.getprototypeof": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz",
-            "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1",
-                "globalthis": "^1.0.3",
-                "which-builtin-type": "^1.1.3"
-            }
-        },
-        "regenerate": {
-            "version": "1.4.2",
-            "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
-            "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
-            "dev": true
-        },
-        "regenerate-unicode-properties": {
-            "version": "10.1.0",
-            "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz",
-            "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==",
-            "dev": true,
-            "requires": {
-                "regenerate": "^1.4.2"
-            }
-        },
-        "regenerator-runtime": {
-            "version": "0.14.0",
-            "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz",
-            "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
-        },
-        "regenerator-transform": {
-            "version": "0.15.2",
-            "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
-            "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
-            "dev": true,
-            "requires": {
-                "@babel/runtime": "^7.8.4"
-            }
-        },
-        "regex-parser": {
-            "version": "2.2.11",
-            "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz",
-            "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==",
-            "dev": true
-        },
-        "regexp.prototype.flags": {
-            "version": "1.5.2",
-            "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
-            "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.6",
-                "define-properties": "^1.2.1",
-                "es-errors": "^1.3.0",
-                "set-function-name": "^2.0.1"
-            }
-        },
-        "regexpu-core": {
-            "version": "5.3.2",
-            "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz",
-            "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==",
-            "dev": true,
-            "requires": {
-                "@babel/regjsgen": "^0.8.0",
-                "regenerate": "^1.4.2",
-                "regenerate-unicode-properties": "^10.1.0",
-                "regjsparser": "^0.9.1",
-                "unicode-match-property-ecmascript": "^2.0.0",
-                "unicode-match-property-value-ecmascript": "^2.1.0"
-            }
-        },
-        "regjsparser": {
-            "version": "0.9.1",
-            "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
-            "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==",
-            "dev": true,
-            "requires": {
-                "jsesc": "~0.5.0"
-            },
-            "dependencies": {
-                "jsesc": {
-                    "version": "0.5.0",
-                    "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-                    "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
-                    "dev": true
-                }
-            }
-        },
-        "relateurl": {
-            "version": "0.2.7",
-            "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
-            "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
-            "dev": true
-        },
-        "replace-ext": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
-            "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
-            "dev": true
-        },
-        "require-directory": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-            "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
-            "dev": true
-        },
-        "require-from-string": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
-            "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
-            "dev": true
-        },
-        "requires-port": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-            "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
-            "dev": true
-        },
-        "resolve": {
-            "version": "1.22.4",
-            "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
-            "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
-            "dev": true,
-            "requires": {
-                "is-core-module": "^2.13.0",
-                "path-parse": "^1.0.7",
-                "supports-preserve-symlinks-flag": "^1.0.0"
-            }
-        },
-        "resolve-cwd": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
-            "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
-            "dev": true,
-            "requires": {
-                "resolve-from": "^5.0.0"
-            },
-            "dependencies": {
-                "resolve-from": {
-                    "version": "5.0.0",
-                    "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
-                    "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
-                    "dev": true
-                }
-            }
-        },
-        "resolve-from": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-            "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-            "dev": true
-        },
-        "resolve-url-loader": {
-            "version": "5.0.0",
-            "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz",
-            "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==",
-            "dev": true,
-            "requires": {
-                "adjust-sourcemap-loader": "^4.0.0",
-                "convert-source-map": "^1.7.0",
-                "loader-utils": "^2.0.0",
-                "postcss": "^8.2.14",
-                "source-map": "0.6.1"
-            }
-        },
-        "resolve.exports": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
-            "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==",
-            "dev": true
-        },
-        "retry": {
-            "version": "0.13.1",
-            "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
-            "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
-            "dev": true
-        },
-        "reusify": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
-            "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-            "dev": true
-        },
-        "rimraf": {
-            "version": "3.0.2",
-            "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-            "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-            "dev": true,
-            "requires": {
-                "glob": "^7.1.3"
-            }
-        },
-        "ripemd160": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
-            "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
-            "dev": true,
-            "requires": {
-                "hash-base": "^3.0.0",
-                "inherits": "^2.0.1"
-            }
-        },
-        "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==",
-            "dev": true,
-            "requires": {
-                "queue-microtask": "^1.2.2"
-            }
-        },
-        "safe-array-concat": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz",
-            "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.2.1",
-                "has-symbols": "^1.0.3",
-                "isarray": "^2.0.5"
-            },
-            "dependencies": {
-                "isarray": {
-                    "version": "2.0.5",
-                    "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-                    "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-                    "dev": true
-                }
-            }
-        },
-        "safe-buffer": {
-            "version": "5.2.1",
-            "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-            "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-            "dev": true
-        },
-        "safe-regex-test": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
-            "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
-            "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.1.3",
-                "is-regex": "^1.1.4"
-            }
-        },
-        "safer-buffer": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-            "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-            "dev": true
-        },
-        "sass": {
-            "version": "1.66.1",
-            "resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz",
-            "integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==",
-            "dev": true,
-            "requires": {
-                "chokidar": ">=3.0.0 <4.0.0",
-                "immutable": "^4.0.0",
-                "source-map-js": ">=0.6.2 <2.0.0"
-            }
-        },
-        "sass-loader": {
-            "version": "13.3.2",
-            "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz",
-            "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==",
-            "dev": true,
-            "requires": {
-                "neo-async": "^2.6.2"
-            }
-        },
-        "saxes": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
-            "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
-            "dev": true,
-            "requires": {
-                "xmlchars": "^2.2.0"
-            }
-        },
-        "scheduler": {
-            "version": "0.23.0",
-            "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
-            "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
-            "requires": {
-                "loose-envify": "^1.1.0"
-            }
-        },
-        "schema-utils": {
-            "version": "2.7.1",
-            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
-            "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
-            "dev": true,
-            "requires": {
-                "@types/json-schema": "^7.0.5",
-                "ajv": "^6.12.4",
-                "ajv-keywords": "^3.5.2"
-            }
-        },
-        "select-hose": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
-            "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==",
-            "dev": true
-        },
-        "selfsigned": {
-            "version": "2.1.1",
-            "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz",
-            "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==",
-            "dev": true,
-            "requires": {
-                "node-forge": "^1"
-            }
-        },
-        "semver": {
-            "version": "6.3.1",
-            "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-            "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-            "dev": true
-        },
-        "send": {
-            "version": "0.18.0",
-            "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
-            "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
-            "dev": true,
-            "requires": {
-                "debug": "2.6.9",
-                "depd": "2.0.0",
-                "destroy": "1.2.0",
-                "encodeurl": "~1.0.2",
-                "escape-html": "~1.0.3",
-                "etag": "~1.8.1",
-                "fresh": "0.5.2",
-                "http-errors": "2.0.0",
-                "mime": "1.6.0",
-                "ms": "2.1.3",
-                "on-finished": "2.4.1",
-                "range-parser": "~1.2.1",
-                "statuses": "2.0.1"
-            },
-            "dependencies": {
-                "debug": {
-                    "version": "2.6.9",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-                    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "2.0.0"
-                    },
-                    "dependencies": {
-                        "ms": {
-                            "version": "2.0.0",
-                            "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                            "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-                            "dev": true
-                        }
-                    }
-                },
-                "ms": {
-                    "version": "2.1.3",
-                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-                    "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-                    "dev": true
-                }
-            }
-        },
-        "serialize-javascript": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
-            "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
-            "dev": true,
-            "requires": {
-                "randombytes": "^2.1.0"
-            }
-        },
-        "serve-index": {
-            "version": "1.9.1",
-            "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
-            "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
-            "dev": true,
-            "requires": {
-                "accepts": "~1.3.4",
-                "batch": "0.6.1",
-                "debug": "2.6.9",
-                "escape-html": "~1.0.3",
-                "http-errors": "~1.6.2",
-                "mime-types": "~2.1.17",
-                "parseurl": "~1.3.2"
-            },
-            "dependencies": {
-                "debug": {
-                    "version": "2.6.9",
-                    "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-                    "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-                    "dev": true,
-                    "requires": {
-                        "ms": "2.0.0"
-                    }
-                },
-                "depd": {
-                    "version": "1.1.2",
-                    "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
-                    "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
-                    "dev": true
-                },
-                "http-errors": {
-                    "version": "1.6.3",
-                    "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
-                    "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
-                    "dev": true,
-                    "requires": {
-                        "depd": "~1.1.2",
-                        "inherits": "2.0.3",
-                        "setprototypeof": "1.1.0",
-                        "statuses": ">= 1.4.0 < 2"
-                    }
-                },
-                "inherits": {
-                    "version": "2.0.3",
-                    "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-                    "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
-                    "dev": true
-                },
-                "ms": {
-                    "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-                    "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-                    "dev": true
-                },
-                "setprototypeof": {
-                    "version": "1.1.0",
-                    "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
-                    "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
-                    "dev": true
-                },
-                "statuses": {
-                    "version": "1.5.0",
-                    "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
-                    "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
-                    "dev": true
-                }
-            }
-        },
-        "serve-static": {
-            "version": "1.15.0",
-            "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
-            "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
-            "dev": true,
-            "requires": {
-                "encodeurl": "~1.0.2",
-                "escape-html": "~1.0.3",
-                "parseurl": "~1.3.3",
-                "send": "0.18.0"
-            }
-        },
-        "set-function-length": {
-            "version": "1.2.1",
-            "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
-            "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
-            "requires": {
-                "define-data-property": "^1.1.2",
-                "es-errors": "^1.3.0",
-                "function-bind": "^1.1.2",
-                "get-intrinsic": "^1.2.3",
-                "gopd": "^1.0.1",
-                "has-property-descriptors": "^1.0.1"
-            }
-        },
-        "set-function-name": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
-            "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
-            "dev": true,
-            "requires": {
-                "define-data-property": "^1.1.4",
-                "es-errors": "^1.3.0",
-                "functions-have-names": "^1.2.3",
-                "has-property-descriptors": "^1.0.2"
-            }
-        },
-        "setimmediate": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
-            "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
-            "dev": true
-        },
-        "setprototypeof": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
-            "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
-            "dev": true
-        },
-        "sha.js": {
-            "version": "2.4.11",
-            "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
-            "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
-            "dev": true,
-            "requires": {
-                "inherits": "^2.0.1",
-                "safe-buffer": "^5.0.1"
-            }
-        },
-        "shallow-clone": {
-            "version": "3.0.1",
-            "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
-            "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
-            "dev": true,
-            "requires": {
-                "kind-of": "^6.0.2"
-            }
-        },
-        "shebang-command": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-            "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-            "dev": true,
-            "requires": {
-                "shebang-regex": "^3.0.0"
-            }
-        },
-        "shebang-regex": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-            "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-            "dev": true
-        },
-        "shell-quote": {
-            "version": "1.8.1",
-            "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
-            "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
-            "dev": true
-        },
-        "shellwords": {
-            "version": "0.1.1",
-            "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
-            "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
-            "dev": true
-        },
-        "side-channel": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
-            "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
-            "requires": {
-                "call-bind": "^1.0.0",
-                "get-intrinsic": "^1.0.2",
-                "object-inspect": "^1.9.0"
-            }
-        },
-        "signal-exit": {
-            "version": "3.0.7",
-            "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
-            "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
-            "dev": true
-        },
-        "sisteransi": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
-            "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
-            "dev": true
-        },
-        "slash": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-            "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
-            "dev": true
-        },
-        "sockjs": {
-            "version": "0.3.24",
-            "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
-            "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==",
-            "dev": true,
-            "requires": {
-                "faye-websocket": "^0.11.3",
-                "uuid": "^8.3.2",
-                "websocket-driver": "^0.7.4"
-            }
-        },
-        "source-list-map": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
-            "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
-            "dev": true
-        },
-        "source-map": {
-            "version": "0.6.1",
-            "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-            "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-            "dev": true
-        },
-        "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==",
-            "dev": true
-        },
-        "source-map-support": {
-            "version": "0.5.21",
-            "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
-            "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
-            "dev": true,
-            "requires": {
-                "buffer-from": "^1.0.0",
-                "source-map": "^0.6.0"
-            }
-        },
-        "spdy": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
-            "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
-            "dev": true,
-            "requires": {
-                "debug": "^4.1.0",
-                "handle-thing": "^2.0.0",
-                "http-deceiver": "^1.2.7",
-                "select-hose": "^2.0.0",
-                "spdy-transport": "^3.0.0"
-            }
-        },
-        "spdy-transport": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
-            "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
-            "dev": true,
-            "requires": {
-                "debug": "^4.1.0",
-                "detect-node": "^2.0.4",
-                "hpack.js": "^2.1.6",
-                "obuf": "^1.1.2",
-                "readable-stream": "^3.0.6",
-                "wbuf": "^1.7.3"
-            },
-            "dependencies": {
-                "readable-stream": {
-                    "version": "3.6.2",
-                    "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
-                    "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
-                    "dev": true,
-                    "requires": {
-                        "inherits": "^2.0.3",
-                        "string_decoder": "^1.1.1",
-                        "util-deprecate": "^1.0.1"
-                    }
-                }
-            }
-        },
-        "sprintf-js": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-            "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
-            "dev": true
-        },
-        "stable": {
-            "version": "0.1.8",
-            "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
-            "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
-            "dev": true
-        },
-        "stack-utils": {
-            "version": "2.0.6",
-            "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
-            "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
-            "dev": true,
-            "requires": {
-                "escape-string-regexp": "^2.0.0"
-            },
-            "dependencies": {
-                "escape-string-regexp": {
-                    "version": "2.0.0",
-                    "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
-                    "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
-                    "dev": true
-                }
-            }
-        },
-        "statuses": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
-            "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
-            "dev": true
-        },
-        "std-env": {
-            "version": "3.4.3",
-            "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.3.tgz",
-            "integrity": "sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==",
-            "dev": true
-        },
-        "stop-iteration-iterator": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
-            "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
-            "dev": true,
-            "requires": {
-                "internal-slot": "^1.0.4"
-            }
-        },
-        "stream-browserify": {
-            "version": "2.0.2",
-            "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
-            "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
-            "dev": true,
-            "requires": {
-                "inherits": "~2.0.1",
-                "readable-stream": "^2.0.2"
+                },
+                "ts-node": {
+                    "optional": true
+                }
             }
         },
             }
         },
-        "stream-http": {
-            "version": "2.8.3",
-            "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
-            "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
+        "node_modules/tapable": {
+            "version": "2.2.2",
+            "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz",
+            "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "builtin-status-codes": "^3.0.0",
-                "inherits": "^2.0.1",
-                "readable-stream": "^2.3.6",
-                "to-arraybuffer": "^1.0.0",
-                "xtend": "^4.0.0"
+            "license": "MIT",
+            "engines": {
+                "node": ">=6"
             }
         },
             }
         },
-        "string_decoder": {
-            "version": "1.3.0",
-            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
-            "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+        "node_modules/terser": {
+            "version": "5.43.1",
+            "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
+            "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "safe-buffer": "~5.2.0"
+            "license": "BSD-2-Clause",
+            "dependencies": {
+                "@jridgewell/source-map": "^0.3.3",
+                "acorn": "^8.14.0",
+                "commander": "^2.20.0",
+                "source-map-support": "~0.5.20"
+            },
+            "bin": {
+                "terser": "bin/terser"
+            },
+            "engines": {
+                "node": ">=10"
             }
         },
             }
         },
-        "string-length": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
-            "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+        "node_modules/terser-webpack-plugin": {
+            "version": "5.3.14",
+            "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz",
+            "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "char-regex": "^1.0.2",
-                "strip-ansi": "^6.0.0"
+            "license": "MIT",
+            "dependencies": {
+                "@jridgewell/trace-mapping": "^0.3.25",
+                "jest-worker": "^27.4.5",
+                "schema-utils": "^4.3.0",
+                "serialize-javascript": "^6.0.2",
+                "terser": "^5.31.1"
+            },
+            "engines": {
+                "node": ">= 10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
+            },
+            "peerDependencies": {
+                "webpack": "^5.1.0"
+            },
+            "peerDependenciesMeta": {
+                "@swc/core": {
+                    "optional": true
+                },
+                "esbuild": {
+                    "optional": true
+                },
+                "uglify-js": {
+                    "optional": true
+                }
             }
         },
             }
         },
-        "string-width": {
-            "version": "4.2.3",
-            "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-            "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+        "node_modules/terser-webpack-plugin/node_modules/ajv": {
+            "version": "8.17.1",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+            "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "emoji-regex": "^8.0.0",
-                "is-fullwidth-code-point": "^3.0.0",
-                "strip-ansi": "^6.0.1"
+            "license": "MIT",
+            "dependencies": {
+                "fast-deep-equal": "^3.1.3",
+                "fast-uri": "^3.0.1",
+                "json-schema-traverse": "^1.0.0",
+                "require-from-string": "^2.0.2"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/epoberezkin"
             }
         },
             }
         },
-        "string.prototype.matchall": {
-            "version": "4.0.9",
-            "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.9.tgz",
-            "integrity": "sha512-6i5hL3MqG/K2G43mWXWgP+qizFW/QH/7kCNN13JrJS5q48FN5IKksLDscexKP3dnmB6cdm9jlNgAsWNLpSykmA==",
+        "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+            "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1",
-                "get-intrinsic": "^1.2.1",
-                "has-symbols": "^1.0.3",
-                "internal-slot": "^1.0.5",
-                "regexp.prototype.flags": "^1.5.0",
-                "side-channel": "^1.0.4"
+            "license": "MIT",
+            "dependencies": {
+                "fast-deep-equal": "^3.1.3"
+            },
+            "peerDependencies": {
+                "ajv": "^8.8.2"
             }
         },
             }
         },
-        "string.prototype.trim": {
-            "version": "1.2.7",
-            "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
-            "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
+        "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+            "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "es-abstract": "^1.20.4"
-            }
+            "license": "MIT"
         },
         },
-        "string.prototype.trimend": {
-            "version": "1.0.6",
-            "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
-            "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
+        "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
+            "version": "4.3.2",
+            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
+            "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.1.4",
-                "es-abstract": "^1.20.4"
+            "license": "MIT",
+            "dependencies": {
+                "@types/json-schema": "^7.0.9",
+                "ajv": "^8.9.0",
+                "ajv-formats": "^2.1.1",
+                "ajv-keywords": "^5.1.0"
+            },
+            "engines": {
+                "node": ">= 10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
             }
         },
             }
         },
-        "string.prototype.trimstart": {
-            "version": "1.0.7",
-            "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz",
-            "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==",
+        "node_modules/terser/node_modules/commander": {
+            "version": "2.20.3",
+            "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+            "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "define-properties": "^1.2.0",
-                "es-abstract": "^1.22.1"
-            }
+            "license": "MIT"
         },
         },
-        "strip-ansi": {
-            "version": "6.0.1",
-            "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-            "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+        "node_modules/test-exclude": {
+            "version": "7.0.1",
+            "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz",
+            "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "ansi-regex": "^5.0.1"
+            "license": "ISC",
+            "dependencies": {
+                "@istanbuljs/schema": "^0.1.2",
+                "glob": "^10.4.1",
+                "minimatch": "^9.0.4"
+            },
+            "engines": {
+                "node": ">=18"
             }
         },
             }
         },
-        "strip-bom": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-            "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
-            "dev": true
-        },
-        "strip-final-newline": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
-            "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
-            "dev": true
-        },
-        "strip-indent": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
-            "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+        "node_modules/test-exclude/node_modules/brace-expansion": {
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+            "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "min-indent": "^1.0.0"
+            "license": "MIT",
+            "dependencies": {
+                "balanced-match": "^1.0.0"
             }
         },
             }
         },
-        "strip-json-comments": {
-            "version": "3.1.1",
-            "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-            "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-            "dev": true
-        },
-        "style-loader": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz",
-            "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==",
+        "node_modules/test-exclude/node_modules/glob": {
+            "version": "10.4.5",
+            "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+            "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "loader-utils": "^2.0.0",
-                "schema-utils": "^3.0.0"
-            },
+            "license": "ISC",
             "dependencies": {
             "dependencies": {
-                "schema-utils": {
-                    "version": "3.3.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-                    "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.8",
-                        "ajv": "^6.12.5",
-                        "ajv-keywords": "^3.5.2"
-                    }
-                }
+                "foreground-child": "^3.1.0",
+                "jackspeak": "^3.1.2",
+                "minimatch": "^9.0.4",
+                "minipass": "^7.1.2",
+                "package-json-from-dist": "^1.0.0",
+                "path-scurry": "^1.11.1"
+            },
+            "bin": {
+                "glob": "dist/esm/bin.mjs"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
             }
         },
             }
         },
-        "style-mod": {
-            "version": "4.1.0",
-            "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.0.tgz",
-            "integrity": "sha512-Ca5ib8HrFn+f+0n4N4ScTIA9iTOQ7MaGS1ylHcoVqW9J7w2w8PzN6g9gKmTYgGEBH8e120+RCmhpje6jC5uGWA=="
-        },
-        "stylehacks": {
-            "version": "5.1.1",
-            "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.1.1.tgz",
-            "integrity": "sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==",
+        "node_modules/test-exclude/node_modules/minimatch": {
+            "version": "9.0.5",
+            "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+            "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "browserslist": "^4.21.4",
-                "postcss-selector-parser": "^6.0.4"
+            "license": "ISC",
+            "dependencies": {
+                "brace-expansion": "^2.0.1"
+            },
+            "engines": {
+                "node": ">=16 || 14 >=14.17"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/isaacs"
             }
         },
             }
         },
-        "sucrase": {
-            "version": "3.34.0",
-            "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz",
-            "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==",
+        "node_modules/thenify": {
+            "version": "3.3.1",
+            "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+            "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "@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"
-            },
+            "license": "MIT",
+            "peer": true,
             "dependencies": {
             "dependencies": {
-                "commander": {
-                    "version": "4.1.1",
-                    "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
-                    "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
-                    "dev": true
-                },
-                "glob": {
-                    "version": "7.1.6",
-                    "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-                    "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-                    "dev": true,
-                    "requires": {
-                        "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"
-                    }
-                }
+                "any-promise": "^1.0.0"
             }
         },
             }
         },
-        "supports-color": {
-            "version": "5.5.0",
-            "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-            "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+        "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==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "has-flag": "^3.0.0"
+            "license": "MIT",
+            "peer": true,
+            "dependencies": {
+                "thenify": ">= 3.1.0 < 4"
+            },
+            "engines": {
+                "node": ">=0.8"
             }
         },
             }
         },
-        "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==",
-            "dev": true
+        "node_modules/thunky": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
+            "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "svgo": {
-            "version": "2.8.0",
-            "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz",
-            "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==",
+        "node_modules/timers-browserify": {
+            "version": "2.0.12",
+            "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
+            "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "@trysound/sax": "0.2.0",
-                "commander": "^7.2.0",
-                "css-select": "^4.1.3",
-                "css-tree": "^1.1.3",
-                "csso": "^4.2.0",
-                "picocolors": "^1.0.0",
-                "stable": "^0.1.8"
+            "license": "MIT",
+            "dependencies": {
+                "setimmediate": "^1.0.4"
+            },
+            "engines": {
+                "node": ">=0.6.0"
             }
         },
             }
         },
-        "symbol-tree": {
-            "version": "3.2.4",
-            "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
-            "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
-            "dev": true
+        "node_modules/tiny-case": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
+            "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==",
+            "license": "MIT"
         },
         },
-        "tailwindcss": {
-            "version": "3.3.3",
-            "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz",
-            "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==",
+        "node_modules/tiny-invariant": {
+            "version": "1.3.3",
+            "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+            "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+            "license": "MIT"
+        },
+        "node_modules/tiny-warning": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
+            "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
+            "license": "MIT"
+        },
+        "node_modules/tinybench": {
+            "version": "2.9.0",
+            "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
+            "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "@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.2.12",
-                "glob-parent": "^6.0.2",
-                "is-glob": "^4.0.3",
-                "jiti": "^1.18.2",
-                "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"
-            },
-            "dependencies": {
-                "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==",
-                    "dev": true,
-                    "requires": {
-                        "lilconfig": "^2.0.5",
-                        "yaml": "^2.1.1"
-                    }
-                },
-                "yaml": {
-                    "version": "2.3.2",
-                    "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz",
-                    "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==",
-                    "dev": true
-                }
-            }
+            "license": "MIT"
         },
         },
-        "tapable": {
-            "version": "2.2.1",
-            "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
-            "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
-            "dev": true
+        "node_modules/tinyexec": {
+            "version": "0.3.2",
+            "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
+            "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "terser": {
-            "version": "5.19.4",
-            "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.4.tgz",
-            "integrity": "sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g==",
+        "node_modules/tinyglobby": {
+            "version": "0.2.14",
+            "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
+            "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "@jridgewell/source-map": "^0.3.3",
-                "acorn": "^8.8.2",
-                "commander": "^2.20.0",
-                "source-map-support": "~0.5.20"
-            },
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "commander": {
-                    "version": "2.20.3",
-                    "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-                    "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-                    "dev": true
-                }
+                "fdir": "^6.4.4",
+                "picomatch": "^4.0.2"
+            },
+            "engines": {
+                "node": ">=12.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/SuperchupuDev"
             }
         },
             }
         },
-        "terser-webpack-plugin": {
-            "version": "5.3.9",
-            "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz",
-            "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==",
+        "node_modules/tinyglobby/node_modules/fdir": {
+            "version": "6.4.6",
+            "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
+            "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "@jridgewell/trace-mapping": "^0.3.17",
-                "jest-worker": "^27.4.5",
-                "schema-utils": "^3.1.1",
-                "serialize-javascript": "^6.0.1",
-                "terser": "^5.16.8"
-            },
-            "dependencies": {
-                "schema-utils": {
-                    "version": "3.3.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-                    "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.8",
-                        "ajv": "^6.12.5",
-                        "ajv-keywords": "^3.5.2"
-                    }
+            "license": "MIT",
+            "peerDependencies": {
+                "picomatch": "^3 || ^4"
+            },
+            "peerDependenciesMeta": {
+                "picomatch": {
+                    "optional": true
                 }
             }
         },
                 }
             }
         },
-        "test-exclude": {
-            "version": "6.0.0",
-            "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
-            "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+        "node_modules/tinyglobby/node_modules/picomatch": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+            "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "@istanbuljs/schema": "^0.1.2",
-                "glob": "^7.1.4",
-                "minimatch": "^3.0.4"
+            "license": "MIT",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/jonschlinkert"
             }
         },
             }
         },
-        "text-table": {
-            "version": "0.2.0",
-            "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-            "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
-            "dev": true
-        },
-        "thenify": {
-            "version": "3.3.1",
-            "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
-            "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+        "node_modules/tinypool": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz",
+            "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "any-promise": "^1.0.0"
+            "license": "MIT",
+            "engines": {
+                "node": "^18.0.0 || >=20.0.0"
             }
         },
             }
         },
-        "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==",
+        "node_modules/tinyrainbow": {
+            "version": "2.0.0",
+            "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz",
+            "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "thenify": ">= 3.1.0 < 4"
+            "license": "MIT",
+            "engines": {
+                "node": ">=14.0.0"
             }
         },
             }
         },
-        "thunky": {
-            "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
-            "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
-            "dev": true
-        },
-        "timers-browserify": {
-            "version": "2.0.12",
-            "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
-            "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
+        "node_modules/tinyspy": {
+            "version": "4.0.3",
+            "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz",
+            "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "setimmediate": "^1.0.4"
+            "license": "MIT",
+            "engines": {
+                "node": ">=14.0.0"
             }
         },
             }
         },
-        "tiny-case": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
-            "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
-        },
-        "tiny-warning": {
-            "version": "1.0.3",
-            "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
-            "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
+        "node_modules/tldts": {
+            "version": "6.1.86",
+            "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz",
+            "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "tldts-core": "^6.1.86"
+            },
+            "bin": {
+                "tldts": "bin/cli.js"
+            }
         },
         },
-        "tmpl": {
-            "version": "1.0.5",
-            "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
-            "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
-            "dev": true
+        "node_modules/tldts-core": {
+            "version": "6.1.86",
+            "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz",
+            "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "to-arraybuffer": {
+        "node_modules/to-arraybuffer": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
             "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==",
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
             "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "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==",
-            "dev": true
+        "node_modules/to-buffer": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz",
+            "integrity": "sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "isarray": "^2.0.5",
+                "safe-buffer": "^5.2.1",
+                "typed-array-buffer": "^1.0.3"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            }
+        },
+        "node_modules/to-buffer/node_modules/isarray": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+            "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "to-regex-range": {
+        "node_modules/to-regex-range": {
             "version": "5.0.1",
             "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
             "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
             "dev": true,
             "version": "5.0.1",
             "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
             "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "is-number": "^7.0.0"
                 "is-number": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=8.0"
             }
         },
             }
         },
-        "toastr": {
+        "node_modules/toastr": {
             "version": "2.1.4",
             "resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz",
             "integrity": "sha512-LIy77F5n+sz4tefMmFOntcJ6HL0Fv3k1TDnNmFZ0bU/GcvIIfy6eG2v7zQmMiYgaalAiUv75ttFrPn5s0gyqlA==",
             "version": "2.1.4",
             "resolved": "https://registry.npmjs.org/toastr/-/toastr-2.1.4.tgz",
             "integrity": "sha512-LIy77F5n+sz4tefMmFOntcJ6HL0Fv3k1TDnNmFZ0bU/GcvIIfy6eG2v7zQmMiYgaalAiUv75ttFrPn5s0gyqlA==",
-            "requires": {
+            "dependencies": {
                 "jquery": ">=1.12.0"
             }
         },
                 "jquery": ">=1.12.0"
             }
         },
-        "toidentifier": {
+        "node_modules/toidentifier": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
             "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
             "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.6"
+            }
         },
         },
-        "toposort": {
+        "node_modules/toposort": {
             "version": "2.0.2",
             "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
             "version": "2.0.2",
             "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
-            "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
+            "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==",
+            "license": "MIT"
         },
         },
-        "tough-cookie": {
-            "version": "4.1.3",
-            "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
-            "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
+        "node_modules/tough-cookie": {
+            "version": "5.1.2",
+            "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz",
+            "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "psl": "^1.1.33",
-                "punycode": "^2.1.1",
-                "universalify": "^0.2.0",
-                "url-parse": "^1.5.3"
-            },
+            "license": "BSD-3-Clause",
             "dependencies": {
             "dependencies": {
-                "punycode": {
-                    "version": "2.3.1",
-                    "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-                    "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-                    "dev": true
-                },
-                "universalify": {
-                    "version": "0.2.0",
-                    "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
-                    "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
-                    "dev": true
-                }
+                "tldts": "^6.1.32"
+            },
+            "engines": {
+                "node": ">=16"
             }
         },
             }
         },
-        "tr46": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz",
-            "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==",
+        "node_modules/tr46": {
+            "version": "5.1.1",
+            "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
+            "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "punycode": "^2.1.1"
-            },
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "punycode": {
-                    "version": "2.3.1",
-                    "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-                    "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-                    "dev": true
-                }
+                "punycode": "^2.3.1"
+            },
+            "engines": {
+                "node": ">=18"
+            }
+        },
+        "node_modules/tr46/node_modules/punycode": {
+            "version": "2.3.1",
+            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+            "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=6"
             }
         },
             }
         },
-        "ts-interface-checker": {
+        "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==",
             "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==",
-            "dev": true
+            "dev": true,
+            "license": "Apache-2.0",
+            "peer": true
         },
         },
-        "tsconfig-paths": {
-            "version": "3.14.2",
-            "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
-            "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
+        "node_modules/tsconfig-paths": {
+            "version": "3.15.0",
+            "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+            "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
             "dev": true,
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "@types/json5": "^0.0.29",
                 "json5": "^1.0.2",
                 "minimist": "^1.2.6",
                 "strip-bom": "^3.0.0"
                 "@types/json5": "^0.0.29",
                 "json5": "^1.0.2",
                 "minimist": "^1.2.6",
                 "strip-bom": "^3.0.0"
-            },
+            }
+        },
+        "node_modules/tsconfig-paths/node_modules/json5": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+            "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "json5": {
-                    "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-                    "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-                    "dev": true,
-                    "requires": {
-                        "minimist": "^1.2.0"
-                    }
-                }
+                "minimist": "^1.2.0"
+            },
+            "bin": {
+                "json5": "lib/cli.js"
             }
         },
             }
         },
-        "tslib": {
-            "version": "2.6.2",
-            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
-            "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+        "node_modules/tslib": {
+            "version": "2.8.1",
+            "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+            "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+            "license": "0BSD"
         },
         },
-        "tty-browserify": {
+        "node_modules/tty-browserify": {
             "version": "0.0.0",
             "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
             "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==",
             "version": "0.0.0",
             "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
             "integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "tweetnacl": {
+        "node_modules/tweetnacl": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
-            "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
+            "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
+            "license": "Unlicense"
         },
         },
-        "type-check": {
+        "node_modules/type-check": {
             "version": "0.4.0",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
             "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
             "dev": true,
             "version": "0.4.0",
             "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
             "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "prelude-ls": "^1.2.1"
                 "prelude-ls": "^1.2.1"
+            },
+            "engines": {
+                "node": ">= 0.8.0"
             }
         },
             }
         },
-        "type-detect": {
-            "version": "4.0.8",
-            "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
-            "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
-            "dev": true
-        },
-        "type-fest": {
-            "version": "0.20.2",
-            "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-            "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
-            "dev": true
+        "node_modules/type-fest": {
+            "version": "2.19.0",
+            "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+            "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+            "license": "(MIT OR CC0-1.0)",
+            "engines": {
+                "node": ">=12.20"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
         },
         },
-        "type-is": {
+        "node_modules/type-is": {
             "version": "1.6.18",
             "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
             "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
             "dev": true,
             "version": "1.6.18",
             "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
             "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "media-typer": "0.3.0",
                 "mime-types": "~2.1.24"
                 "media-typer": "0.3.0",
                 "mime-types": "~2.1.24"
+            },
+            "engines": {
+                "node": ">= 0.6"
             }
         },
             }
         },
-        "typed-array-buffer": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz",
-            "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==",
+        "node_modules/typed-array-buffer": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+            "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
-                "get-intrinsic": "^1.2.1",
-                "is-typed-array": "^1.1.10"
+            "license": "MIT",
+            "dependencies": {
+                "call-bound": "^1.0.3",
+                "es-errors": "^1.3.0",
+                "is-typed-array": "^1.1.14"
+            },
+            "engines": {
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "typed-array-byte-length": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz",
-            "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==",
+        "node_modules/typed-array-byte-length": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz",
+            "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
+            "license": "MIT",
+            "dependencies": {
+                "call-bind": "^1.0.8",
                 "for-each": "^0.3.3",
                 "for-each": "^0.3.3",
-                "has-proto": "^1.0.1",
-                "is-typed-array": "^1.1.10"
+                "gopd": "^1.2.0",
+                "has-proto": "^1.2.0",
+                "is-typed-array": "^1.1.14"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "typed-array-byte-offset": {
-            "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz",
-            "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==",
+        "node_modules/typed-array-byte-offset": {
+            "version": "1.0.4",
+            "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+            "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "available-typed-arrays": "^1.0.5",
-                "call-bind": "^1.0.2",
+            "license": "MIT",
+            "dependencies": {
+                "available-typed-arrays": "^1.0.7",
+                "call-bind": "^1.0.8",
                 "for-each": "^0.3.3",
                 "for-each": "^0.3.3",
-                "has-proto": "^1.0.1",
-                "is-typed-array": "^1.1.10"
+                "gopd": "^1.2.0",
+                "has-proto": "^1.2.0",
+                "is-typed-array": "^1.1.15",
+                "reflect.getprototypeof": "^1.0.9"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "typed-array-length": {
-            "version": "1.0.4",
-            "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
-            "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
+        "node_modules/typed-array-length": {
+            "version": "1.0.7",
+            "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
+            "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
+            "license": "MIT",
+            "dependencies": {
+                "call-bind": "^1.0.7",
                 "for-each": "^0.3.3",
                 "for-each": "^0.3.3",
-                "is-typed-array": "^1.1.9"
+                "gopd": "^1.0.1",
+                "is-typed-array": "^1.1.13",
+                "possible-typed-array-names": "^1.0.0",
+                "reflect.getprototypeof": "^1.0.6"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "unbox-primitive": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
-            "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+        "node_modules/unbox-primitive": {
+            "version": "1.1.0",
+            "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+            "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "call-bind": "^1.0.2",
+            "license": "MIT",
+            "dependencies": {
+                "call-bound": "^1.0.3",
                 "has-bigints": "^1.0.2",
                 "has-bigints": "^1.0.2",
-                "has-symbols": "^1.0.3",
-                "which-boxed-primitive": "^1.0.2"
+                "has-symbols": "^1.1.0",
+                "which-boxed-primitive": "^1.1.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "uncontrollable": {
+        "node_modules/uncontrollable": {
             "version": "7.2.1",
             "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
             "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
             "version": "7.2.1",
             "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
             "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "@babel/runtime": "^7.6.3",
                 "@types/react": ">=16.9.11",
                 "invariant": "^2.2.4",
                 "react-lifecycles-compat": "^3.0.4"
                 "@babel/runtime": "^7.6.3",
                 "@types/react": ">=16.9.11",
                 "invariant": "^2.2.4",
                 "react-lifecycles-compat": "^3.0.4"
+            },
+            "peerDependencies": {
+                "react": ">=15.0.0"
             }
         },
             }
         },
-        "unicode-canonical-property-names-ecmascript": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
-            "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
-            "dev": true
+        "node_modules/undici-types": {
+            "version": "7.8.0",
+            "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
+            "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "unicode-match-property-ecmascript": {
+        "node_modules/unicode-canonical-property-names-ecmascript": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
+            "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
+        },
+        "node_modules/unicode-match-property-ecmascript": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
             "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
             "dev": true,
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
             "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "unicode-canonical-property-names-ecmascript": "^2.0.0",
                 "unicode-property-aliases-ecmascript": "^2.0.0"
                 "unicode-canonical-property-names-ecmascript": "^2.0.0",
                 "unicode-property-aliases-ecmascript": "^2.0.0"
+            },
+            "engines": {
+                "node": ">=4"
             }
         },
             }
         },
-        "unicode-match-property-value-ecmascript": {
-            "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
-            "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
-            "dev": true
+        "node_modules/unicode-match-property-value-ecmascript": {
+            "version": "2.2.0",
+            "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz",
+            "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
         },
         },
-        "unicode-property-aliases-ecmascript": {
+        "node_modules/unicode-property-aliases-ecmascript": {
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
             "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
             "version": "2.1.0",
             "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
             "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=4"
+            }
         },
         },
-        "universalify": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
-            "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
-            "dev": true
+        "node_modules/universalify": {
+            "version": "2.0.1",
+            "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+            "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 10.0.0"
+            }
         },
         },
-        "unpipe": {
+        "node_modules/unpipe": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
             "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
             "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
         },
         },
-        "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==",
+        "node_modules/update-browserslist-db": {
+            "version": "1.1.3",
+            "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+            "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "escalade": "^3.1.1",
-                "picocolors": "^1.0.0"
+            "funding": [
+                {
+                    "type": "opencollective",
+                    "url": "https://opencollective.com/browserslist"
+                },
+                {
+                    "type": "tidelift",
+                    "url": "https://tidelift.com/funding/github/npm/browserslist"
+                },
+                {
+                    "type": "github",
+                    "url": "https://github.com/sponsors/ai"
+                }
+            ],
+            "license": "MIT",
+            "dependencies": {
+                "escalade": "^3.2.0",
+                "picocolors": "^1.1.1"
+            },
+            "bin": {
+                "update-browserslist-db": "cli.js"
+            },
+            "peerDependencies": {
+                "browserslist": ">= 4.21.0"
             }
         },
             }
         },
-        "uri-js": {
+        "node_modules/uri-js": {
             "version": "4.4.1",
             "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
             "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
             "dev": true,
             "version": "4.4.1",
             "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
             "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
             "dev": true,
-            "requires": {
-                "punycode": "^2.1.0"
-            },
+            "license": "BSD-2-Clause",
             "dependencies": {
             "dependencies": {
-                "punycode": {
-                    "version": "2.3.0",
-                    "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
-                    "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
-                    "dev": true
-                }
+                "punycode": "^2.1.0"
             }
         },
             }
         },
-        "url": {
-            "version": "0.11.1",
-            "resolved": "https://registry.npmjs.org/url/-/url-0.11.1.tgz",
-            "integrity": "sha512-rWS3H04/+mzzJkv0eZ7vEDGiQbgquI1fGfOad6zKvgYQi1SzMmhl7c/DdRGxhaWrVH6z0qWITo8rpnxK/RfEhA==",
+        "node_modules/uri-js/node_modules/punycode": {
+            "version": "2.3.1",
+            "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+            "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "punycode": "^1.4.1",
-                "qs": "^6.11.0"
+            "license": "MIT",
+            "engines": {
+                "node": ">=6"
             }
         },
             }
         },
-        "url-parse": {
-            "version": "1.5.10",
-            "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
-            "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+        "node_modules/url": {
+            "version": "0.11.4",
+            "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz",
+            "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "querystringify": "^2.1.1",
-                "requires-port": "^1.0.0"
+            "license": "MIT",
+            "dependencies": {
+                "punycode": "^1.4.1",
+                "qs": "^6.12.3"
+            },
+            "engines": {
+                "node": ">= 0.4"
             }
         },
             }
         },
-        "util": {
+        "node_modules/util": {
             "version": "0.11.1",
             "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
             "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
             "dev": true,
             "version": "0.11.1",
             "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
             "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
             "dev": true,
-            "requires": {
-                "inherits": "2.0.3"
-            },
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "inherits": {
-                    "version": "2.0.3",
-                    "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-                    "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
-                    "dev": true
-                }
+                "inherits": "2.0.3"
             }
         },
             }
         },
-        "util-deprecate": {
+        "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==",
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
             "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/util/node_modules/inherits": {
+            "version": "2.0.3",
+            "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+            "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
+            "dev": true,
+            "license": "ISC"
         },
         },
-        "utils-merge": {
+        "node_modules/utils-merge": {
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
             "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
             "version": "1.0.1",
             "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
             "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.4.0"
+            }
         },
         },
-        "uuid": {
+        "node_modules/uuid": {
             "version": "8.3.2",
             "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
             "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
             "version": "8.3.2",
             "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
             "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
-            "dev": true
-        },
-        "v8-to-istanbul": {
-            "version": "9.2.0",
-            "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz",
-            "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "@jridgewell/trace-mapping": "^0.3.12",
-                "@types/istanbul-lib-coverage": "^2.0.1",
-                "convert-source-map": "^2.0.0"
-            },
-            "dependencies": {
-                "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==",
-                    "dev": true
-                }
+            "license": "MIT",
+            "bin": {
+                "uuid": "dist/bin/uuid"
             }
         },
             }
         },
-        "vary": {
+        "node_modules/vary": {
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
             "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
             "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">= 0.8"
+            }
         },
         },
-        "victory-vendor": {
-            "version": "36.6.11",
-            "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.6.11.tgz",
-            "integrity": "sha512-nT8kCiJp8dQh8g991J/R5w5eE2KnO8EAIP0xocWlh9l2okngMWglOPoMZzJvek8Q1KUc4XE/mJxTZnvOB1sTYg==",
-            "requires": {
+        "node_modules/victory-vendor": {
+            "version": "36.9.2",
+            "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
+            "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==",
+            "license": "MIT AND ISC",
+            "dependencies": {
                 "@types/d3-array": "^3.0.3",
                 "@types/d3-ease": "^3.0.0",
                 "@types/d3-interpolate": "^3.0.1",
                 "@types/d3-array": "^3.0.3",
                 "@types/d3-ease": "^3.0.0",
                 "@types/d3-interpolate": "^3.0.1",
                 "d3-timer": "^3.0.1"
             }
         },
                 "d3-timer": "^3.0.1"
             }
         },
-        "vm-browserify": {
+        "node_modules/vite": {
+            "version": "6.3.5",
+            "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
+            "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "esbuild": "^0.25.0",
+                "fdir": "^6.4.4",
+                "picomatch": "^4.0.2",
+                "postcss": "^8.5.3",
+                "rollup": "^4.34.9",
+                "tinyglobby": "^0.2.13"
+            },
+            "bin": {
+                "vite": "bin/vite.js"
+            },
+            "engines": {
+                "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+            },
+            "funding": {
+                "url": "https://github.com/vitejs/vite?sponsor=1"
+            },
+            "optionalDependencies": {
+                "fsevents": "~2.3.3"
+            },
+            "peerDependencies": {
+                "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+                "jiti": ">=1.21.0",
+                "less": "*",
+                "lightningcss": "^1.21.0",
+                "sass": "*",
+                "sass-embedded": "*",
+                "stylus": "*",
+                "sugarss": "*",
+                "terser": "^5.16.0",
+                "tsx": "^4.8.1",
+                "yaml": "^2.4.2"
+            },
+            "peerDependenciesMeta": {
+                "@types/node": {
+                    "optional": true
+                },
+                "jiti": {
+                    "optional": true
+                },
+                "less": {
+                    "optional": true
+                },
+                "lightningcss": {
+                    "optional": true
+                },
+                "sass": {
+                    "optional": true
+                },
+                "sass-embedded": {
+                    "optional": true
+                },
+                "stylus": {
+                    "optional": true
+                },
+                "sugarss": {
+                    "optional": true
+                },
+                "terser": {
+                    "optional": true
+                },
+                "tsx": {
+                    "optional": true
+                },
+                "yaml": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/vite-node": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
+            "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "cac": "^6.7.14",
+                "debug": "^4.4.1",
+                "es-module-lexer": "^1.7.0",
+                "pathe": "^2.0.3",
+                "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+            },
+            "bin": {
+                "vite-node": "vite-node.mjs"
+            },
+            "engines": {
+                "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            }
+        },
+        "node_modules/vite-plugin-full-reload": {
+            "version": "1.2.0",
+            "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz",
+            "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "picocolors": "^1.0.0",
+                "picomatch": "^2.3.1"
+            }
+        },
+        "node_modules/vite-plugin-webpackchunkname": {
+            "version": "1.0.3",
+            "resolved": "https://registry.npmjs.org/vite-plugin-webpackchunkname/-/vite-plugin-webpackchunkname-1.0.3.tgz",
+            "integrity": "sha512-88lt6IrgCumnf4Up8eyaSJbmo4V0ZIaR4M94fbZvGGmK2aWMmPGVsiFBszYE7Kq04I9tGjLFnyremn+KEgEGyw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@rollup/plugin-alias": "*",
+                "@rollup/pluginutils": "*",
+                "es-module-lexer": "*",
+                "magic-string": "*"
+            }
+        },
+        "node_modules/vite/node_modules/fdir": {
+            "version": "6.4.6",
+            "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
+            "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
+            "dev": true,
+            "license": "MIT",
+            "peerDependencies": {
+                "picomatch": "^3 || ^4"
+            },
+            "peerDependenciesMeta": {
+                "picomatch": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/vite/node_modules/picomatch": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+            "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/jonschlinkert"
+            }
+        },
+        "node_modules/vitest": {
+            "version": "3.2.4",
+            "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz",
+            "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/chai": "^5.2.2",
+                "@vitest/expect": "3.2.4",
+                "@vitest/mocker": "3.2.4",
+                "@vitest/pretty-format": "^3.2.4",
+                "@vitest/runner": "3.2.4",
+                "@vitest/snapshot": "3.2.4",
+                "@vitest/spy": "3.2.4",
+                "@vitest/utils": "3.2.4",
+                "chai": "^5.2.0",
+                "debug": "^4.4.1",
+                "expect-type": "^1.2.1",
+                "magic-string": "^0.30.17",
+                "pathe": "^2.0.3",
+                "picomatch": "^4.0.2",
+                "std-env": "^3.9.0",
+                "tinybench": "^2.9.0",
+                "tinyexec": "^0.3.2",
+                "tinyglobby": "^0.2.14",
+                "tinypool": "^1.1.1",
+                "tinyrainbow": "^2.0.0",
+                "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0",
+                "vite-node": "3.2.4",
+                "why-is-node-running": "^2.3.0"
+            },
+            "bin": {
+                "vitest": "vitest.mjs"
+            },
+            "engines": {
+                "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+            },
+            "funding": {
+                "url": "https://opencollective.com/vitest"
+            },
+            "peerDependencies": {
+                "@edge-runtime/vm": "*",
+                "@types/debug": "^4.1.12",
+                "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+                "@vitest/browser": "3.2.4",
+                "@vitest/ui": "3.2.4",
+                "happy-dom": "*",
+                "jsdom": "*"
+            },
+            "peerDependenciesMeta": {
+                "@edge-runtime/vm": {
+                    "optional": true
+                },
+                "@types/debug": {
+                    "optional": true
+                },
+                "@types/node": {
+                    "optional": true
+                },
+                "@vitest/browser": {
+                    "optional": true
+                },
+                "@vitest/ui": {
+                    "optional": true
+                },
+                "happy-dom": {
+                    "optional": true
+                },
+                "jsdom": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/vitest/node_modules/picomatch": {
+            "version": "4.0.2",
+            "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
+            "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=12"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/jonschlinkert"
+            }
+        },
+        "node_modules/vm-browserify": {
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
             "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
             "version": "1.1.2",
             "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
             "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "void-elements": {
+        "node_modules/void-elements": {
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
             "version": "3.1.0",
             "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
-            "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="
+            "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
         },
         },
-        "vue-style-loader": {
+        "node_modules/vue-style-loader": {
             "version": "4.1.3",
             "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
             "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==",
             "dev": true,
             "version": "4.1.3",
             "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.3.tgz",
             "integrity": "sha512-sFuh0xfbtpRlKfm39ss/ikqs9AbKCoXZBpHeVZ8Tx650o0k0q/YCM7FRvigtxpACezfq6af+a7JeqVTWvncqDg==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "hash-sum": "^1.0.2",
                 "loader-utils": "^1.0.2"
                 "hash-sum": "^1.0.2",
                 "loader-utils": "^1.0.2"
+            }
+        },
+        "node_modules/vue-style-loader/node_modules/json5": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+            "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "minimist": "^1.2.0"
             },
             },
+            "bin": {
+                "json5": "lib/cli.js"
+            }
+        },
+        "node_modules/vue-style-loader/node_modules/loader-utils": {
+            "version": "1.4.2",
+            "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
+            "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "json5": {
-                    "version": "1.0.2",
-                    "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-                    "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-                    "dev": true,
-                    "requires": {
-                        "minimist": "^1.2.0"
-                    }
-                },
-                "loader-utils": {
-                    "version": "1.4.2",
-                    "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.2.tgz",
-                    "integrity": "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==",
-                    "dev": true,
-                    "requires": {
-                        "big.js": "^5.2.2",
-                        "emojis-list": "^3.0.0",
-                        "json5": "^1.0.1"
-                    }
-                }
+                "big.js": "^5.2.2",
+                "emojis-list": "^3.0.0",
+                "json5": "^1.0.1"
+            },
+            "engines": {
+                "node": ">=4.0.0"
             }
         },
             }
         },
-        "w3c-keyname": {
+        "node_modules/w3c-keyname": {
             "version": "2.2.8",
             "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
             "version": "2.2.8",
             "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
-            "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="
+            "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
+            "license": "MIT"
         },
         },
-        "w3c-xmlserializer": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
-            "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==",
-            "dev": true,
-            "requires": {
-                "xml-name-validator": "^4.0.0"
-            }
-        },
-        "walker": {
-            "version": "1.0.8",
-            "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
-            "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+        "node_modules/w3c-xmlserializer": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+            "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "makeerror": "1.0.12"
+            "license": "MIT",
+            "dependencies": {
+                "xml-name-validator": "^5.0.0"
+            },
+            "engines": {
+                "node": ">=18"
             }
         },
             }
         },
-        "warning": {
+        "node_modules/warning": {
             "version": "4.0.3",
             "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
             "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
             "version": "4.0.3",
             "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
             "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "loose-envify": "^1.0.0"
             }
         },
                 "loose-envify": "^1.0.0"
             }
         },
-        "watchpack": {
-            "version": "2.4.0",
-            "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
-            "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
+        "node_modules/watchpack": {
+            "version": "2.4.4",
+            "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
+            "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
             "dev": true,
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "glob-to-regexp": "^0.4.1",
                 "graceful-fs": "^4.1.2"
                 "glob-to-regexp": "^0.4.1",
                 "graceful-fs": "^4.1.2"
+            },
+            "engines": {
+                "node": ">=10.13.0"
             }
         },
             }
         },
-        "wbuf": {
+        "node_modules/wbuf": {
             "version": "1.7.3",
             "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
             "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
             "dev": true,
             "version": "1.7.3",
             "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
             "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "minimalistic-assert": "^1.0.0"
             }
         },
                 "minimalistic-assert": "^1.0.0"
             }
         },
-        "webidl-conversions": {
+        "node_modules/webidl-conversions": {
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
             "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
             "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
-            "dev": true
-        },
-        "webpack": {
-            "version": "5.88.2",
-            "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz",
-            "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "@types/eslint-scope": "^3.7.3",
-                "@types/estree": "^1.0.0",
-                "@webassemblyjs/ast": "^1.11.5",
-                "@webassemblyjs/wasm-edit": "^1.11.5",
-                "@webassemblyjs/wasm-parser": "^1.11.5",
-                "acorn": "^8.7.1",
-                "acorn-import-assertions": "^1.9.0",
-                "browserslist": "^4.14.5",
+            "license": "BSD-2-Clause",
+            "engines": {
+                "node": ">=12"
+            }
+        },
+        "node_modules/webpack": {
+            "version": "5.99.9",
+            "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz",
+            "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/eslint-scope": "^3.7.7",
+                "@types/estree": "^1.0.6",
+                "@types/json-schema": "^7.0.15",
+                "@webassemblyjs/ast": "^1.14.1",
+                "@webassemblyjs/wasm-edit": "^1.14.1",
+                "@webassemblyjs/wasm-parser": "^1.14.1",
+                "acorn": "^8.14.0",
+                "browserslist": "^4.24.0",
                 "chrome-trace-event": "^1.0.2",
                 "chrome-trace-event": "^1.0.2",
-                "enhanced-resolve": "^5.15.0",
+                "enhanced-resolve": "^5.17.1",
                 "es-module-lexer": "^1.2.1",
                 "eslint-scope": "5.1.1",
                 "events": "^3.2.0",
                 "glob-to-regexp": "^0.4.1",
                 "es-module-lexer": "^1.2.1",
                 "eslint-scope": "5.1.1",
                 "events": "^3.2.0",
                 "glob-to-regexp": "^0.4.1",
-                "graceful-fs": "^4.2.9",
+                "graceful-fs": "^4.2.11",
                 "json-parse-even-better-errors": "^2.3.1",
                 "loader-runner": "^4.2.0",
                 "mime-types": "^2.1.27",
                 "neo-async": "^2.6.2",
                 "json-parse-even-better-errors": "^2.3.1",
                 "loader-runner": "^4.2.0",
                 "mime-types": "^2.1.27",
                 "neo-async": "^2.6.2",
-                "schema-utils": "^3.2.0",
+                "schema-utils": "^4.3.2",
                 "tapable": "^2.1.1",
                 "tapable": "^2.1.1",
-                "terser-webpack-plugin": "^5.3.7",
-                "watchpack": "^2.4.0",
+                "terser-webpack-plugin": "^5.3.11",
+                "watchpack": "^2.4.1",
                 "webpack-sources": "^3.2.3"
             },
                 "webpack-sources": "^3.2.3"
             },
-            "dependencies": {
-                "schema-utils": {
-                    "version": "3.3.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
-                    "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.8",
-                        "ajv": "^6.12.5",
-                        "ajv-keywords": "^3.5.2"
-                    }
-                },
-                "webpack-sources": {
-                    "version": "3.2.3",
-                    "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
-                    "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
-                    "dev": true
+            "bin": {
+                "webpack": "bin/webpack.js"
+            },
+            "engines": {
+                "node": ">=10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
+            },
+            "peerDependenciesMeta": {
+                "webpack-cli": {
+                    "optional": true
                 }
             }
         },
                 }
             }
         },
-        "webpack-cli": {
+        "node_modules/webpack-cli": {
             "version": "4.10.0",
             "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
             "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
             "dev": true,
             "version": "4.10.0",
             "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
             "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "@discoveryjs/json-ext": "^0.5.0",
                 "@webpack-cli/configtest": "^1.2.0",
                 "@webpack-cli/info": "^1.5.0",
                 "@discoveryjs/json-ext": "^0.5.0",
                 "@webpack-cli/configtest": "^1.2.0",
                 "@webpack-cli/info": "^1.5.0",
                 "interpret": "^2.2.0",
                 "rechoir": "^0.7.0",
                 "webpack-merge": "^5.7.3"
                 "interpret": "^2.2.0",
                 "rechoir": "^0.7.0",
                 "webpack-merge": "^5.7.3"
+            },
+            "bin": {
+                "webpack-cli": "bin/cli.js"
+            },
+            "engines": {
+                "node": ">=10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
+            },
+            "peerDependencies": {
+                "webpack": "4.x.x || 5.x.x"
+            },
+            "peerDependenciesMeta": {
+                "@webpack-cli/generators": {
+                    "optional": true
+                },
+                "@webpack-cli/migrate": {
+                    "optional": true
+                },
+                "webpack-bundle-analyzer": {
+                    "optional": true
+                },
+                "webpack-dev-server": {
+                    "optional": true
+                }
             }
         },
             }
         },
-        "webpack-dev-middleware": {
-            "version": "5.3.3",
-            "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
-            "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
+        "node_modules/webpack-dev-middleware": {
+            "version": "5.3.4",
+            "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz",
+            "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==",
             "dev": true,
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "colorette": "^2.0.10",
                 "memfs": "^3.4.3",
                 "mime-types": "^2.1.31",
                 "range-parser": "^1.2.1",
                 "schema-utils": "^4.0.0"
             },
                 "colorette": "^2.0.10",
                 "memfs": "^3.4.3",
                 "mime-types": "^2.1.31",
                 "range-parser": "^1.2.1",
                 "schema-utils": "^4.0.0"
             },
+            "engines": {
+                "node": ">= 12.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
+            },
+            "peerDependencies": {
+                "webpack": "^4.0.0 || ^5.0.0"
+            }
+        },
+        "node_modules/webpack-dev-middleware/node_modules/ajv": {
+            "version": "8.17.1",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+            "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ajv": {
-                    "version": "8.12.0",
-                    "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
-                    "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
-                    "dev": true,
-                    "requires": {
-                        "fast-deep-equal": "^3.1.1",
-                        "json-schema-traverse": "^1.0.0",
-                        "require-from-string": "^2.0.2",
-                        "uri-js": "^4.2.2"
-                    }
-                },
-                "ajv-keywords": {
-                    "version": "5.1.0",
-                    "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
-                    "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
-                    "dev": true,
-                    "requires": {
-                        "fast-deep-equal": "^3.1.3"
-                    }
-                },
-                "json-schema-traverse": {
-                    "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
-                    "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
-                    "dev": true
-                },
-                "schema-utils": {
-                    "version": "4.2.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
-                    "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.9",
-                        "ajv": "^8.9.0",
-                        "ajv-formats": "^2.1.1",
-                        "ajv-keywords": "^5.1.0"
-                    }
-                }
+                "fast-deep-equal": "^3.1.3",
+                "fast-uri": "^3.0.1",
+                "json-schema-traverse": "^1.0.0",
+                "require-from-string": "^2.0.2"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/epoberezkin"
+            }
+        },
+        "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+            "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "fast-deep-equal": "^3.1.3"
+            },
+            "peerDependencies": {
+                "ajv": "^8.8.2"
+            }
+        },
+        "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+            "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/webpack-dev-middleware/node_modules/schema-utils": {
+            "version": "4.3.2",
+            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
+            "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/json-schema": "^7.0.9",
+                "ajv": "^8.9.0",
+                "ajv-formats": "^2.1.1",
+                "ajv-keywords": "^5.1.0"
+            },
+            "engines": {
+                "node": ">= 10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
             }
         },
             }
         },
-        "webpack-dev-server": {
-            "version": "4.15.1",
-            "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz",
-            "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==",
+        "node_modules/webpack-dev-server": {
+            "version": "4.15.2",
+            "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
+            "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
             "dev": true,
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "@types/bonjour": "^3.5.9",
                 "@types/connect-history-api-fallback": "^1.3.5",
                 "@types/express": "^4.17.13",
                 "@types/bonjour": "^3.5.9",
                 "@types/connect-history-api-fallback": "^1.3.5",
                 "@types/express": "^4.17.13",
                 "serve-index": "^1.9.1",
                 "sockjs": "^0.3.24",
                 "spdy": "^4.0.2",
                 "serve-index": "^1.9.1",
                 "sockjs": "^0.3.24",
                 "spdy": "^4.0.2",
-                "webpack-dev-middleware": "^5.3.1",
+                "webpack-dev-middleware": "^5.3.4",
                 "ws": "^8.13.0"
             },
                 "ws": "^8.13.0"
             },
-            "dependencies": {
-                "ajv": {
-                    "version": "8.12.0",
-                    "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
-                    "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
-                    "dev": true,
-                    "requires": {
-                        "fast-deep-equal": "^3.1.1",
-                        "json-schema-traverse": "^1.0.0",
-                        "require-from-string": "^2.0.2",
-                        "uri-js": "^4.2.2"
-                    }
-                },
-                "ajv-keywords": {
-                    "version": "5.1.0",
-                    "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
-                    "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
-                    "dev": true,
-                    "requires": {
-                        "fast-deep-equal": "^3.1.3"
-                    }
-                },
-                "json-schema-traverse": {
-                    "version": "1.0.0",
-                    "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
-                    "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
-                    "dev": true
+            "bin": {
+                "webpack-dev-server": "bin/webpack-dev-server.js"
+            },
+            "engines": {
+                "node": ">= 12.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
+            },
+            "peerDependencies": {
+                "webpack": "^4.37.0 || ^5.0.0"
+            },
+            "peerDependenciesMeta": {
+                "webpack": {
+                    "optional": true
                 },
                 },
-                "schema-utils": {
-                    "version": "4.2.0",
-                    "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
-                    "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
-                    "dev": true,
-                    "requires": {
-                        "@types/json-schema": "^7.0.9",
-                        "ajv": "^8.9.0",
-                        "ajv-formats": "^2.1.1",
-                        "ajv-keywords": "^5.1.0"
-                    }
+                "webpack-cli": {
+                    "optional": true
                 }
             }
         },
                 }
             }
         },
-        "webpack-merge": {
-            "version": "5.9.0",
-            "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.9.0.tgz",
-            "integrity": "sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==",
+        "node_modules/webpack-dev-server/node_modules/ajv": {
+            "version": "8.17.1",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+            "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "fast-deep-equal": "^3.1.3",
+                "fast-uri": "^3.0.1",
+                "json-schema-traverse": "^1.0.0",
+                "require-from-string": "^2.0.2"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/epoberezkin"
+            }
+        },
+        "node_modules/webpack-dev-server/node_modules/ajv-keywords": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+            "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "fast-deep-equal": "^3.1.3"
+            },
+            "peerDependencies": {
+                "ajv": "^8.8.2"
+            }
+        },
+        "node_modules/webpack-dev-server/node_modules/json-schema-traverse": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+            "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/webpack-dev-server/node_modules/schema-utils": {
+            "version": "4.3.2",
+            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
+            "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/json-schema": "^7.0.9",
+                "ajv": "^8.9.0",
+                "ajv-formats": "^2.1.1",
+                "ajv-keywords": "^5.1.0"
+            },
+            "engines": {
+                "node": ">= 10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
+            }
+        },
+        "node_modules/webpack-merge": {
+            "version": "5.10.0",
+            "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz",
+            "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==",
             "dev": true,
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "clone-deep": "^4.0.1",
                 "clone-deep": "^4.0.1",
+                "flat": "^5.0.2",
                 "wildcard": "^2.0.0"
                 "wildcard": "^2.0.0"
+            },
+            "engines": {
+                "node": ">=10.0.0"
             }
         },
             }
         },
-        "webpack-notifier": {
+        "node_modules/webpack-notifier": {
             "version": "1.15.0",
             "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.15.0.tgz",
             "integrity": "sha512-N2V8UMgRB5komdXQRavBsRpw0hPhJq2/SWNOGuhrXpIgRhcMexzkGQysUyGStHLV5hkUlgpRiF7IUXoBqyMmzQ==",
             "dev": true,
             "version": "1.15.0",
             "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.15.0.tgz",
             "integrity": "sha512-N2V8UMgRB5komdXQRavBsRpw0hPhJq2/SWNOGuhrXpIgRhcMexzkGQysUyGStHLV5hkUlgpRiF7IUXoBqyMmzQ==",
             "dev": true,
-            "requires": {
+            "license": "ISC",
+            "dependencies": {
                 "node-notifier": "^9.0.0",
                 "strip-ansi": "^6.0.0"
                 "node-notifier": "^9.0.0",
                 "strip-ansi": "^6.0.0"
+            },
+            "peerDependencies": {
+                "@types/webpack": ">4.41.31"
+            },
+            "peerDependenciesMeta": {
+                "@types/webpack": {
+                    "optional": true
+                }
+            }
+        },
+        "node_modules/webpack-sources": {
+            "version": "1.4.3",
+            "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
+            "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "source-list-map": "^2.0.0",
+                "source-map": "~0.6.1"
+            }
+        },
+        "node_modules/webpack/node_modules/ajv": {
+            "version": "8.17.1",
+            "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+            "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "fast-deep-equal": "^3.1.3",
+                "fast-uri": "^3.0.1",
+                "json-schema-traverse": "^1.0.0",
+                "require-from-string": "^2.0.2"
+            },
+            "funding": {
+                "type": "github",
+                "url": "https://github.com/sponsors/epoberezkin"
+            }
+        },
+        "node_modules/webpack/node_modules/ajv-keywords": {
+            "version": "5.1.0",
+            "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+            "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "fast-deep-equal": "^3.1.3"
+            },
+            "peerDependencies": {
+                "ajv": "^8.8.2"
+            }
+        },
+        "node_modules/webpack/node_modules/json-schema-traverse": {
+            "version": "1.0.0",
+            "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+            "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/webpack/node_modules/schema-utils": {
+            "version": "4.3.2",
+            "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
+            "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
+            "dev": true,
+            "license": "MIT",
+            "dependencies": {
+                "@types/json-schema": "^7.0.9",
+                "ajv": "^8.9.0",
+                "ajv-formats": "^2.1.1",
+                "ajv-keywords": "^5.1.0"
+            },
+            "engines": {
+                "node": ">= 10.13.0"
+            },
+            "funding": {
+                "type": "opencollective",
+                "url": "https://opencollective.com/webpack"
             }
         },
             }
         },
-        "webpack-sources": {
-            "version": "1.4.3",
-            "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
-            "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
+        "node_modules/webpack/node_modules/webpack-sources": {
+            "version": "3.3.3",
+            "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz",
+            "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "source-list-map": "^2.0.0",
-                "source-map": "~0.6.1"
+            "license": "MIT",
+            "engines": {
+                "node": ">=10.13.0"
             }
         },
             }
         },
-        "webpackbar": {
+        "node_modules/webpackbar": {
             "version": "5.0.2",
             "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz",
             "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==",
             "dev": true,
             "version": "5.0.2",
             "resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.2.tgz",
             "integrity": "sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "chalk": "^4.1.0",
                 "consola": "^2.15.3",
                 "pretty-time": "^1.1.0",
                 "std-env": "^3.0.1"
             },
                 "chalk": "^4.1.0",
                 "consola": "^2.15.3",
                 "pretty-time": "^1.1.0",
                 "std-env": "^3.0.1"
             },
+            "engines": {
+                "node": ">=12"
+            },
+            "peerDependencies": {
+                "webpack": "3 || 4 || 5"
+            }
+        },
+        "node_modules/webpackbar/node_modules/chalk": {
+            "version": "4.1.2",
+            "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+            "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "chalk": {
-                    "version": "4.1.2",
-                    "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
-                    "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
-                    "dev": true,
-                    "requires": {
-                        "ansi-styles": "^4.1.0",
-                        "supports-color": "^7.1.0"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                },
-                "has-flag": {
-                    "version": "4.0.0",
-                    "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-                    "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-                    "dev": true
-                },
-                "supports-color": {
-                    "version": "7.2.0",
-                    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-                    "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-                    "dev": true,
-                    "requires": {
-                        "has-flag": "^4.0.0"
-                    }
-                }
+                "ansi-styles": "^4.1.0",
+                "supports-color": "^7.1.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/chalk?sponsor=1"
             }
         },
             }
         },
-        "websocket-driver": {
+        "node_modules/websocket-driver": {
             "version": "0.7.4",
             "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
             "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
             "dev": true,
             "version": "0.7.4",
             "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
             "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
             "dev": true,
-            "requires": {
+            "license": "Apache-2.0",
+            "dependencies": {
                 "http-parser-js": ">=0.5.1",
                 "safe-buffer": ">=5.1.0",
                 "websocket-extensions": ">=0.1.1"
                 "http-parser-js": ">=0.5.1",
                 "safe-buffer": ">=5.1.0",
                 "websocket-extensions": ">=0.1.1"
+            },
+            "engines": {
+                "node": ">=0.8.0"
             }
         },
             }
         },
-        "websocket-extensions": {
+        "node_modules/websocket-extensions": {
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
             "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
             "version": "0.1.4",
             "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
             "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
-            "dev": true
+            "dev": true,
+            "license": "Apache-2.0",
+            "engines": {
+                "node": ">=0.8.0"
+            }
         },
         },
-        "whatwg-encoding": {
-            "version": "2.0.0",
-            "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz",
-            "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==",
+        "node_modules/whatwg-encoding": {
+            "version": "3.1.1",
+            "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+            "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
             "dev": true,
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "iconv-lite": "0.6.3"
             },
                 "iconv-lite": "0.6.3"
             },
+            "engines": {
+                "node": ">=18"
+            }
+        },
+        "node_modules/whatwg-encoding/node_modules/iconv-lite": {
+            "version": "0.6.3",
+            "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+            "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "iconv-lite": {
-                    "version": "0.6.3",
-                    "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
-                    "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
-                    "dev": true,
-                    "requires": {
-                        "safer-buffer": ">= 2.1.2 < 3.0.0"
-                    }
-                }
+                "safer-buffer": ">= 2.1.2 < 3.0.0"
+            },
+            "engines": {
+                "node": ">=0.10.0"
             }
         },
             }
         },
-        "whatwg-mimetype": {
-            "version": "3.0.0",
-            "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz",
-            "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==",
-            "dev": true
+        "node_modules/whatwg-mimetype": {
+            "version": "4.0.0",
+            "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+            "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=18"
+            }
         },
         },
-        "whatwg-url": {
-            "version": "11.0.0",
-            "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz",
-            "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==",
+        "node_modules/whatwg-url": {
+            "version": "14.2.0",
+            "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
+            "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "tr46": "^3.0.0",
+            "license": "MIT",
+            "dependencies": {
+                "tr46": "^5.1.0",
                 "webidl-conversions": "^7.0.0"
                 "webidl-conversions": "^7.0.0"
+            },
+            "engines": {
+                "node": ">=18"
             }
         },
             }
         },
-        "which": {
+        "node_modules/which": {
             "version": "2.0.2",
             "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
             "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
             "dev": true,
             "version": "2.0.2",
             "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
             "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
             "dev": true,
-            "requires": {
+            "license": "ISC",
+            "dependencies": {
                 "isexe": "^2.0.0"
                 "isexe": "^2.0.0"
+            },
+            "bin": {
+                "node-which": "bin/node-which"
+            },
+            "engines": {
+                "node": ">= 8"
             }
         },
             }
         },
-        "which-boxed-primitive": {
-            "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
-            "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+        "node_modules/which-boxed-primitive": {
+            "version": "1.1.1",
+            "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz",
+            "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "is-bigint": "^1.0.1",
-                "is-boolean-object": "^1.1.0",
-                "is-number-object": "^1.0.4",
-                "is-string": "^1.0.5",
-                "is-symbol": "^1.0.3"
+            "license": "MIT",
+            "dependencies": {
+                "is-bigint": "^1.1.0",
+                "is-boolean-object": "^1.2.1",
+                "is-number-object": "^1.1.1",
+                "is-string": "^1.1.1",
+                "is-symbol": "^1.1.1"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "which-builtin-type": {
-            "version": "1.1.3",
-            "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz",
-            "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==",
+        "node_modules/which-builtin-type": {
+            "version": "1.2.1",
+            "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz",
+            "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "function.prototype.name": "^1.1.5",
-                "has-tostringtag": "^1.0.0",
+            "license": "MIT",
+            "dependencies": {
+                "call-bound": "^1.0.2",
+                "function.prototype.name": "^1.1.6",
+                "has-tostringtag": "^1.0.2",
                 "is-async-function": "^2.0.0",
                 "is-async-function": "^2.0.0",
-                "is-date-object": "^1.0.5",
-                "is-finalizationregistry": "^1.0.2",
+                "is-date-object": "^1.1.0",
+                "is-finalizationregistry": "^1.1.0",
                 "is-generator-function": "^1.0.10",
                 "is-generator-function": "^1.0.10",
-                "is-regex": "^1.1.4",
+                "is-regex": "^1.2.1",
                 "is-weakref": "^1.0.2",
                 "isarray": "^2.0.5",
                 "is-weakref": "^1.0.2",
                 "isarray": "^2.0.5",
-                "which-boxed-primitive": "^1.0.2",
-                "which-collection": "^1.0.1",
-                "which-typed-array": "^1.1.9"
+                "which-boxed-primitive": "^1.1.0",
+                "which-collection": "^1.0.2",
+                "which-typed-array": "^1.1.16"
             },
             },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
+            }
+        },
+        "node_modules/which-builtin-type/node_modules/isarray": {
+            "version": "2.0.5",
+            "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+            "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+            "dev": true,
+            "license": "MIT"
+        },
+        "node_modules/which-collection": {
+            "version": "1.0.2",
+            "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
+            "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "isarray": {
-                    "version": "2.0.5",
-                    "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-                    "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-                    "dev": true
-                }
+                "is-map": "^2.0.3",
+                "is-set": "^2.0.3",
+                "is-weakmap": "^2.0.2",
+                "is-weakset": "^2.0.3"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "which-collection": {
-            "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz",
-            "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==",
+        "node_modules/which-typed-array": {
+            "version": "1.1.19",
+            "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
+            "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "is-map": "^2.0.1",
-                "is-set": "^2.0.1",
-                "is-weakmap": "^2.0.1",
-                "is-weakset": "^2.0.1"
+            "license": "MIT",
+            "dependencies": {
+                "available-typed-arrays": "^1.0.7",
+                "call-bind": "^1.0.8",
+                "call-bound": "^1.0.4",
+                "for-each": "^0.3.5",
+                "get-proto": "^1.0.1",
+                "gopd": "^1.2.0",
+                "has-tostringtag": "^1.0.2"
+            },
+            "engines": {
+                "node": ">= 0.4"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/ljharb"
             }
         },
             }
         },
-        "which-typed-array": {
-            "version": "1.1.14",
-            "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz",
-            "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==",
+        "node_modules/why-is-node-running": {
+            "version": "2.3.0",
+            "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
+            "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "available-typed-arrays": "^1.0.6",
-                "call-bind": "^1.0.5",
-                "for-each": "^0.3.3",
-                "gopd": "^1.0.1",
-                "has-tostringtag": "^1.0.1"
+            "license": "MIT",
+            "dependencies": {
+                "siginfo": "^2.0.0",
+                "stackback": "0.0.2"
+            },
+            "bin": {
+                "why-is-node-running": "cli.js"
+            },
+            "engines": {
+                "node": ">=8"
             }
         },
             }
         },
-        "wildcard": {
+        "node_modules/wildcard": {
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
             "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
             "version": "2.0.1",
             "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
             "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "wrap-ansi": {
+        "node_modules/word-wrap": {
+            "version": "1.2.5",
+            "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+            "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.10.0"
+            }
+        },
+        "node_modules/wrap-ansi": {
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
             "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
             "dev": true,
             "version": "7.0.0",
             "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
             "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "ansi-styles": "^4.0.0",
                 "string-width": "^4.1.0",
                 "strip-ansi": "^6.0.0"
             },
                 "ansi-styles": "^4.0.0",
                 "string-width": "^4.1.0",
                 "strip-ansi": "^6.0.0"
             },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+            }
+        },
+        "node_modules/wrap-ansi-cjs": {
+            "name": "wrap-ansi",
+            "version": "7.0.0",
+            "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+            "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+            "dev": true,
+            "license": "MIT",
             "dependencies": {
             "dependencies": {
-                "ansi-styles": {
-                    "version": "4.3.0",
-                    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-                    "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-                    "dev": true,
-                    "requires": {
-                        "color-convert": "^2.0.1"
-                    }
-                },
-                "color-convert": {
-                    "version": "2.0.1",
-                    "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-                    "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-                    "dev": true,
-                    "requires": {
-                        "color-name": "~1.1.4"
-                    }
-                },
-                "color-name": {
-                    "version": "1.1.4",
-                    "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-                    "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-                    "dev": true
-                }
+                "ansi-styles": "^4.0.0",
+                "string-width": "^4.1.0",
+                "strip-ansi": "^6.0.0"
+            },
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
             }
         },
             }
         },
-        "wrappy": {
+        "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==",
             "version": "1.0.2",
             "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
             "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-            "dev": true
+            "dev": true,
+            "license": "ISC"
         },
         },
-        "write-file-atomic": {
-            "version": "4.0.2",
-            "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
-            "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+        "node_modules/ws": {
+            "version": "8.18.2",
+            "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
+            "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
             "dev": true,
             "dev": true,
-            "requires": {
-                "imurmurhash": "^0.1.4",
-                "signal-exit": "^3.0.7"
+            "license": "MIT",
+            "engines": {
+                "node": ">=10.0.0"
+            },
+            "peerDependencies": {
+                "bufferutil": "^4.0.1",
+                "utf-8-validate": ">=5.0.2"
+            },
+            "peerDependenciesMeta": {
+                "bufferutil": {
+                    "optional": true
+                },
+                "utf-8-validate": {
+                    "optional": true
+                }
             }
         },
             }
         },
-        "ws": {
-            "version": "8.13.0",
-            "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
-            "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
+        "node_modules/xml-name-validator": {
+            "version": "5.0.0",
+            "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+            "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
             "dev": true,
             "dev": true,
-            "requires": {}
-        },
-        "xml-name-validator": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
-            "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==",
-            "dev": true
+            "license": "Apache-2.0",
+            "engines": {
+                "node": ">=18"
+            }
         },
         },
-        "xmlchars": {
+        "node_modules/xmlchars": {
             "version": "2.2.0",
             "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
             "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
             "version": "2.2.0",
             "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
             "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
-            "dev": true
+            "dev": true,
+            "license": "MIT"
         },
         },
-        "xtend": {
+        "node_modules/xtend": {
             "version": "4.0.2",
             "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
             "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
             "version": "4.0.2",
             "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
             "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=0.4"
+            }
         },
         },
-        "y18n": {
+        "node_modules/y18n": {
             "version": "5.0.8",
             "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
             "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
             "version": "5.0.8",
             "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
             "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
-            "dev": true
+            "dev": true,
+            "license": "ISC",
+            "engines": {
+                "node": ">=10"
+            }
         },
         },
-        "yallist": {
+        "node_modules/yallist": {
             "version": "3.1.1",
             "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
             "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
             "version": "3.1.1",
             "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
             "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-            "dev": true
+            "dev": true,
+            "license": "ISC"
         },
         },
-        "yaml": {
-            "version": "1.10.2",
-            "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
-            "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
-            "dev": true
+        "node_modules/yaml": {
+            "version": "2.8.0",
+            "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
+            "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
+            "dev": true,
+            "license": "ISC",
+            "peer": true,
+            "bin": {
+                "yaml": "bin.mjs"
+            },
+            "engines": {
+                "node": ">= 14.6"
+            }
         },
         },
-        "yargs": {
+        "node_modules/yargs": {
             "version": "17.7.2",
             "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
             "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
             "dev": true,
             "version": "17.7.2",
             "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
             "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
             "dev": true,
-            "requires": {
+            "license": "MIT",
+            "dependencies": {
                 "cliui": "^8.0.1",
                 "escalade": "^3.1.1",
                 "get-caller-file": "^2.0.5",
                 "cliui": "^8.0.1",
                 "escalade": "^3.1.1",
                 "get-caller-file": "^2.0.5",
                 "string-width": "^4.2.3",
                 "y18n": "^5.0.5",
                 "yargs-parser": "^21.1.1"
                 "string-width": "^4.2.3",
                 "y18n": "^5.0.5",
                 "yargs-parser": "^21.1.1"
+            },
+            "engines": {
+                "node": ">=12"
             }
         },
             }
         },
-        "yargs-parser": {
+        "node_modules/yargs-parser": {
             "version": "21.1.1",
             "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
             "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
             "version": "21.1.1",
             "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
             "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
-            "dev": true
+            "dev": true,
+            "license": "ISC",
+            "engines": {
+                "node": ">=12"
+            }
         },
         },
-        "yocto-queue": {
+        "node_modules/yocto-queue": {
             "version": "0.1.0",
             "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
             "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
             "version": "0.1.0",
             "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
             "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
-            "dev": true
+            "dev": true,
+            "license": "MIT",
+            "engines": {
+                "node": ">=10"
+            },
+            "funding": {
+                "url": "https://github.com/sponsors/sindresorhus"
+            }
         },
         },
-        "yup": {
-            "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/yup/-/yup-1.2.0.tgz",
-            "integrity": "sha512-PPqYKSAXjpRCgLgLKVGPA33v5c/WgEx3wi6NFjIiegz90zSwyMpvTFp/uGcVnnbx6to28pgnzp/q8ih3QRjLMQ==",
-            "requires": {
+        "node_modules/yup": {
+            "version": "1.6.1",
+            "resolved": "https://registry.npmjs.org/yup/-/yup-1.6.1.tgz",
+            "integrity": "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==",
+            "license": "MIT",
+            "dependencies": {
                 "property-expr": "^2.0.5",
                 "tiny-case": "^1.0.3",
                 "toposort": "^2.0.2",
                 "type-fest": "^2.19.0"
                 "property-expr": "^2.0.5",
                 "tiny-case": "^1.0.3",
                 "toposort": "^2.0.2",
                 "type-fest": "^2.19.0"
-            },
-            "dependencies": {
-                "type-fest": {
-                    "version": "2.19.0",
-                    "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
-                    "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="
-                }
             }
         }
     }
             }
         }
     }
index 00152a895b8f857733e6cbe0df9bfedba45904ec..b51ad973eece9efcdb25d1f7dc3b4716d6eb649c 100644 (file)
@@ -1,98 +1,10 @@
 {
     "private": true,
     "scripts": {
 {
     "private": true,
     "scripts": {
-        "dev": "npm run development",
-        "development": "mix",
-        "watch": "mix watch",
-        "watch-poll": "mix watch -- --watch-options-poll=1000",
-        "hot": "mix watch --hot",
-        "prod": "npm run production",
-        "production": "mix --production",
-        "test": "NODE_ENV=test npx jest",
-        "test-watch": "npm run test -- --watch --notify"
-    },
-    "eslintConfig": {
-        "env": {
-            "browser": true,
-            "es6": true,
-            "node": true
-        },
-        "extends": [
-            "eslint:recommended",
-            "plugin:import/recommended",
-            "plugin:react/recommended"
-        ],
-        "parser": "@babel/eslint-parser",
-        "parserOptions": {
-            "babelOptions": {
-                "presets": [
-                    "@babel/preset-react"
-                ]
-            },
-            "ecmaFeatures": {
-                "jsx": true
-            },
-            "ecmaVersion": 2018,
-            "requireConfigFile": false,
-            "sourceType": "module"
-        },
-        "rules": {
-            "import/no-named-as-default-member": 0,
-            "max-len": [
-                "warn",
-                {
-                    "code": 100,
-                    "tabWidth": 4
-                }
-            ],
-            "no-use-before-define": "error",
-            "no-extra-parens": [
-                "warn",
-                "all",
-                {
-                    "nestedBinaryExpressions": false
-                }
-            ],
-            "no-mixed-operators": "error",
-            "no-trailing-spaces": "error",
-            "semi": [
-                "error",
-                "always"
-            ]
-        },
-        "overrides": [
-            {
-                "files": [
-                    "**/*.test.js"
-                ],
-                "env": {
-                    "jest": true
-                },
-                "settings": {
-                    "import/resolver": {
-                        "node": {
-                            "paths": [
-                                "resources/js"
-                            ]
-                        }
-                    }
-                }
-            }
-        ]
-    },
-    "jest": {
-        "moduleDirectories": [
-            "node_modules",
-            "resources/js"
-        ],
-        "roots": [
-            "<rootDir>/resources/js",
-            "<rootDir>/tests/js"
-        ],
-        "setupFilesAfterEnv": [
-            "<rootDir>/resources/js/setup-jest.js"
-        ],
-        "testEnvironment": "jsdom"
+        "dev": "vite",
+        "build": "vite build",
+        "test": "vitest run",
+        "test-watch": "vitest"
     },
     "devDependencies": {
         "@babel/eslint-parser": "^7.22.11",
     },
     "devDependencies": {
         "@babel/eslint-parser": "^7.22.11",
         "@popperjs/core": "^2.10.2",
         "@tailwindcss/forms": "^0.5.6",
         "@testing-library/jest-dom": "^6.4.2",
         "@popperjs/core": "^2.10.2",
         "@tailwindcss/forms": "^0.5.6",
         "@testing-library/jest-dom": "^6.4.2",
-        "@testing-library/react": "^14.2.1",
+        "@testing-library/react": "^16.3.0",
+        "@vitejs/plugin-react": "^4.5.2",
+        "@vitest/coverage-v8": "^3.2.4",
         "alpinejs": "^3.4.2",
         "autoprefixer": "^10.4.2",
         "axios": "^1.5.0",
         "alpinejs": "^3.4.2",
         "autoprefixer": "^10.4.2",
         "axios": "^1.5.0",
-        "babel-jest": "^29.7.0",
         "bootstrap": "^5.1.3",
         "bootstrap": "^5.1.3",
-        "eslint": "^8.10.0",
+        "eslint": "^9.29.0",
         "eslint-plugin-import": "^2.25.4",
         "eslint-plugin-react": "^7.29.3",
         "eslint-plugin-import": "^2.25.4",
         "eslint-plugin-react": "^7.29.3",
-        "jest": "^29.7.0",
-        "jest-environment-jsdom": "^29.7.0",
+        "globals": "^16.2.0",
+        "i18next": "^25.2.1",
+        "jsdom": "^26.1.0",
         "laravel-mix": "^6.0.6",
         "laravel-mix": "^6.0.6",
+        "laravel-vite-plugin": "^1.3.0",
         "lodash": "^4.17.19",
         "postcss": "^8.4.6",
         "lodash": "^4.17.19",
         "postcss": "^8.4.6",
-        "postcss-import": "^15.1.0",
-        "react": "^18.2.0",
-        "react-dom": "^18.2.0",
+        "react": "19.1.0",
+        "react-dom": "19.1.0",
         "resolve-url-loader": "^5.0.0",
         "sass": "^1.32.11",
         "resolve-url-loader": "^5.0.0",
         "sass": "^1.32.11",
-        "sass-loader": "^13.3.2",
-        "tailwindcss": "^3.0.18"
+        "vite": "^6.3.5",
+        "vite-plugin-webpackchunkname": "^1.0.3",
+        "vitest": "^3.2.4"
     },
     "dependencies": {
         "@codemirror/lang-html": "^6.4.5",
     },
     "dependencies": {
         "@codemirror/lang-html": "^6.4.5",
         "d3-drag": "^3.0.0",
         "file-saver": "^2.0.5",
         "formik": "^2.2.9",
         "d3-drag": "^3.0.0",
         "file-saver": "^2.0.5",
         "formik": "^2.2.9",
-        "i18next": "^23.4.9",
-        "i18next-browser-languagedetector": "^7.1.0",
-        "laravel-echo": "^1.11.3",
+        "fuzzy-search": "^3.2.1",
+        "i18next-browser-languagedetector": "^8.0.0",
+        "laravel-echo": "^1.16.1",
         "localforage": "^1.10.0",
         "moment": "^2.29.1",
         "numeral": "^2.0.6",
         "localforage": "^1.10.0",
         "moment": "^2.29.1",
         "numeral": "^2.0.6",
         "qs": "^6.10.3",
         "react-bootstrap": "^2.2.0",
         "react-helmet": "^6.1.0",
         "qs": "^6.10.3",
         "react-bootstrap": "^2.2.0",
         "react-helmet": "^6.1.0",
-        "react-i18next": "^13.2.2",
+        "react-i18next": "^15.0.1",
         "react-router-bootstrap": "^0.26.0",
         "react-router-dom": "^6.2.2",
         "recharts": "^2.1.9",
         "toastr": "^2.1.4",
         "yup": "^1.2.0"
         "react-router-bootstrap": "^0.26.0",
         "react-router-dom": "^6.2.2",
         "recharts": "^2.1.9",
         "toastr": "^2.1.4",
         "yup": "^1.2.0"
-    }
+    },
+    "type": "module"
 }
 }
index 2ac86a1858718f2ae64117738c11442ea18dbdfd..8f80490e33c41ec7ac3d5478ba63487c22aa9735 100644 (file)
@@ -1,31 +1,27 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
-         bootstrap="vendor/autoload.php"
-         colors="true"
->
-    <testsuites>
-        <testsuite name="Unit">
-            <directory suffix="Test.php">./tests/Unit</directory>
-        </testsuite>
-        <testsuite name="Feature">
-            <directory suffix="Test.php">./tests/Feature</directory>
-        </testsuite>
-    </testsuites>
-    <coverage processUncoveredFiles="true">
-        <include>
-            <directory suffix=".php">./app</directory>
-        </include>
-    </coverage>
-    <php>
-        <env name="APP_ENV" value="testing"/>
-        <env name="BCRYPT_ROUNDS" value="4"/>
-        <env name="CACHE_DRIVER" value="array"/>
-        <!-- <env name="DB_CONNECTION" value="sqlite"/> -->
-        <!-- <env name="DB_DATABASE" value=":memory:"/> -->
-        <env name="MAIL_MAILER" value="array"/>
-        <env name="QUEUE_CONNECTION" value="sync"/>
-        <env name="SESSION_DRIVER" value="array"/>
-        <env name="TELESCOPE_ENABLED" value="false"/>
-    </php>
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.3/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" cacheDirectory=".phpunit.cache">
+  <testsuites>
+    <testsuite name="Unit">
+      <directory suffix="Test.php">./tests/Unit</directory>
+    </testsuite>
+    <testsuite name="Feature">
+      <directory suffix="Test.php">./tests/Feature</directory>
+    </testsuite>
+  </testsuites>
+  <php>
+    <env name="APP_ENV" value="testing"/>
+    <env name="BCRYPT_ROUNDS" value="4"/>
+    <env name="CACHE_DRIVER" value="array"/>
+    <!-- <env name="DB_CONNECTION" value="sqlite"/> -->
+    <!-- <env name="DB_DATABASE" value=":memory:"/> -->
+    <env name="MAIL_MAILER" value="array"/>
+    <env name="QUEUE_CONNECTION" value="sync"/>
+    <env name="SESSION_DRIVER" value="array"/>
+    <env name="TELESCOPE_ENABLED" value="false"/>
+  </php>
+  <source>
+    <include>
+      <directory suffix=".php">./app</directory>
+    </include>
+  </source>
 </phpunit>
 </phpunit>
index caa0d5f4af0da9aafd2fa9a39cdcc4570ac9c0c2..ee9d4a0c3346d7d5c5e0474cd611ccf000b81d1f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit caa0d5f4af0da9aafd2fa9a39cdcc4570ac9c0c2
+Subproject commit ee9d4a0c3346d7d5c5e0474cd611ccf000b81d1f
diff --git a/public/muffins-smz3 b/public/muffins-smz3
new file mode 160000 (submodule)
index 0000000..b25a43f
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit b25a43f7f7ae4cc170cbf710eed440f34dda5ed2
index 02a3c038b862f3e4a463c351cb8154fe53243fe1..587d1510cc45378a54174e273b6eeaa1feab530c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 02a3c038b862f3e4a463c351cb8154fe53243fe1
+Subproject commit 587d1510cc45378a54174e273b6eeaa1feab530c
diff --git a/resources/js/app/Footer.js b/resources/js/app/Footer.js
deleted file mode 100644 (file)
index 54af553..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-import React from 'react';
-import { Col, Nav, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-import { LinkContainer } from 'react-router-bootstrap';
-
-import PrivacyDialog from './PrivacyDialog';
-
-const Footer = () => {
-       const [showDialog, setShowDialog] = React.useState(false);
-
-       const { t } = useTranslation();
-
-       return <footer className="bg-dark mt-5 px-3 py-5">
-               <Row>
-                       <Col md={4}>
-                               <h5>{t('footer.competitions')}</h5>
-                               <Nav as="ul" className="flex-column">
-                                       <Nav.Item as="li">
-                                               <LinkContainer to="/tournaments/6">
-                                                       <Nav.Link className="p-0 text-muted" href="/tournaments/6">
-                                                               Deutsche ALttP Community - Seed der Woche
-                                                       </Nav.Link>
-                                               </LinkContainer>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <LinkContainer to="/schedule">
-                                                       <Nav.Link className="p-0 text-muted" href="/schedule">
-                                                               {t('footer.schedule')}
-                                                       </Nav.Link>
-                                               </LinkContainer>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <LinkContainer to="/events">
-                                                       <Nav.Link className="p-0 text-muted" href="/events">
-                                                               {t('footer.events')}
-                                                       </Nav.Link>
-                                               </LinkContainer>
-                                       </Nav.Item>
-                               </Nav>
-                       </Col>
-                       <Col md={4}>
-                               <h5>{t('footer.resources')}</h5>
-                               <Nav as="ul" className="flex-column">
-                                       <Nav.Item as="li">
-                                               <Nav.Link
-                                                       className="p-0 text-muted"
-                                                       href="https://alttp-wiki.net/"
-                                                       target="_blank"
-                                               >
-                                                       {t('footer.alttpwiki')}
-                                               </Nav.Link>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <LinkContainer to="/tech">
-                                                       <Nav.Link className="p-0 text-muted" href="/tech">
-                                                               {t('footer.tech')}
-                                                       </Nav.Link>
-                                               </LinkContainer>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <LinkContainer to="/map">
-                                                       <Nav.Link className="p-0 text-muted" href="/map">
-                                                               {t('footer.map')}
-                                                       </Nav.Link>
-                                               </LinkContainer>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <Nav.Link
-                                                       className="p-0 text-muted"
-                                                       href="https://glitchmaps.mfns.dev/"
-                                                       target="_blank"
-                                               >
-                                                       {t('footer.muffins')}
-                                               </Nav.Link>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <Nav.Link
-                                                       className="p-0 text-muted"
-                                                       href="https://wiki.supermetroid.run/"
-                                                       target="_blank"
-                                               >
-                                                       {t('footer.smwiki')}
-                                               </Nav.Link>
-                                       </Nav.Item>
-                               </Nav>
-                       </Col>
-                       <Col md={4}>
-                               <h5>{t('footer.info')}</h5>
-                               <Nav as="ul" className="flex-column">
-                                       <Nav.Item as="li">
-                                               <Nav.Link
-                                                       className="p-0 text-muted"
-                                                       onClick={() => { setShowDialog(true); }}
-                                               >
-                                                       {t('footer.privacy')}
-                                               </Nav.Link>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <Nav.Link
-                                                       className="p-0 text-muted"
-                                                       href="https://discord.gg/5zuANcS"
-                                                       target="_blank"
-                                               >
-                                                       {t('footer.alttpde')}
-                                               </Nav.Link>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <Nav.Link
-                                                       className="p-0 text-muted"
-                                                       href="https://discord.com/invite/GGdrbnQmVs"
-                                                       target="_blank"
-                                               >
-                                                       {t('footer.smd')}
-                                               </Nav.Link>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <Nav.Link
-                                                       className="p-0 text-muted"
-                                                       href="https://discord.gg/hVw5Zeq"
-                                                       target="_blank"
-                                               >
-                                                       {t('footer.connect')}
-                                               </Nav.Link>
-                                       </Nav.Item>
-                                       <Nav.Item as="li">
-                                               <Nav.Link
-                                                       className="p-0 text-muted"
-                                                       href="https://discord.gg/cx6nZkekXz"
-                                                       target="_blank"
-                                               >
-                                                       {t('footer.restreamCentral')}
-                                               </Nav.Link>
-                                       </Nav.Item>
-                               </Nav>
-                       </Col>
-               </Row>
-               <p className="pt-5 text-center text-muted">{t('footer.contact')}</p>
-               <PrivacyDialog onHide={() => { setShowDialog(false); }} show={showDialog} />
-       </footer>;
-};
-
-export default Footer;
diff --git a/resources/js/app/Footer.jsx b/resources/js/app/Footer.jsx
new file mode 100644 (file)
index 0000000..e3e58bd
--- /dev/null
@@ -0,0 +1,167 @@
+import React from 'react';
+import { Col, Nav, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import { LinkContainer } from 'react-router-bootstrap';
+
+import PrivacyDialog from './PrivacyDialog';
+
+const Footer = () => {
+       const [showDialog, setShowDialog] = React.useState(false);
+
+       const { t } = useTranslation();
+
+       return <div className="bg-dark mt-5 px-3 py-5">
+               <Row>
+                       <Col md={4}>
+                               <h5>{t('footer.competitions')}</h5>
+                               <Nav as="ul" className="flex-column">
+                                       <Nav.Item as="li">
+                                               <LinkContainer to="/tournaments/6">
+                                                       <Nav.Link className="p-0 text-muted" href="/tournaments/6">
+                                                               {t('footer.sdw')}
+                                                       </Nav.Link>
+                                               </LinkContainer>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <LinkContainer to="/tournaments/7">
+                                                       <Nav.Link className="p-0 text-muted" href="/tournaments/7">
+                                                               {t('footer.circus')}
+                                                       </Nav.Link>
+                                               </LinkContainer>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <LinkContainer to="/schedule">
+                                                       <Nav.Link className="p-0 text-muted" href="/schedule">
+                                                               {t('footer.schedule')}
+                                                       </Nav.Link>
+                                               </LinkContainer>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <LinkContainer to="/events">
+                                                       <Nav.Link className="p-0 text-muted" href="/events">
+                                                               {t('footer.events')}
+                                                       </Nav.Link>
+                                               </LinkContainer>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://alttprasyncs.com/"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.alttprasyncs')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://smz3asyncs.com/"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.smz3asyncs')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                               </Nav>
+                       </Col>
+                       <Col md={4}>
+                               <h5>{t('footer.resources')}</h5>
+                               <Nav as="ul" className="flex-column">
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://alttp-wiki.net/"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.alttpwiki')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <LinkContainer to="/tech">
+                                                       <Nav.Link className="p-0 text-muted" href="/tech">
+                                                               {t('footer.tech')}
+                                                       </Nav.Link>
+                                               </LinkContainer>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <LinkContainer to="/map">
+                                                       <Nav.Link className="p-0 text-muted" href="/map">
+                                                               {t('footer.map')}
+                                                       </Nav.Link>
+                                               </LinkContainer>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://glitchmaps.mfns.dev/"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.muffins')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://wiki.supermetroid.run/"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.smwiki')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                               </Nav>
+                       </Col>
+                       <Col md={4}>
+                               <h5>{t('footer.info')}</h5>
+                               <Nav as="ul" className="flex-column">
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       onClick={() => { setShowDialog(true); }}
+                                               >
+                                                       {t('footer.privacy')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://discord.gg/5zuANcS"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.alttpde')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://discord.com/invite/GGdrbnQmVs"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.smd')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://discord.gg/yVdTkEZhk6"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.stepladder')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                                       <Nav.Item as="li">
+                                               <Nav.Link
+                                                       className="p-0 text-muted"
+                                                       href="https://discord.gg/cx6nZkekXz"
+                                                       target="_blank"
+                                               >
+                                                       {t('footer.restreamCentral')}
+                                               </Nav.Link>
+                                       </Nav.Item>
+                               </Nav>
+                       </Col>
+               </Row>
+               <p className="pt-5 text-center text-muted">{t('footer.contact')}</p>
+               <PrivacyDialog onHide={() => { setShowDialog(false); }} show={showDialog} />
+       </div>;
+};
+
+export default Footer;
diff --git a/resources/js/app/FullLayout.js b/resources/js/app/FullLayout.js
deleted file mode 100644 (file)
index 29a7be2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import { Outlet } from 'react-router-dom';
-
-import Footer from './Footer';
-import Header from './Header';
-
-const FullLayout = () => <>
-       <Header />
-       <Outlet />
-       <Footer />
-</>;
-
-export default FullLayout;
diff --git a/resources/js/app/FullLayout.jsx b/resources/js/app/FullLayout.jsx
new file mode 100644 (file)
index 0000000..1771a07
--- /dev/null
@@ -0,0 +1,19 @@
+import React from 'react';
+import { Outlet } from 'react-router-dom';
+
+import Footer from './Footer';
+import Header from './Header';
+
+const FullLayout = () => <>
+       <header>
+               <Header />
+       </header>
+       <main>
+               <Outlet />
+       </main>
+       <footer>
+               <Footer />
+       </footer>
+</>;
+
+export default FullLayout;
diff --git a/resources/js/app/Header.js b/resources/js/app/Header.js
deleted file mode 100644 (file)
index ce30c32..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from 'react';
-import { Container, Nav, Navbar } from 'react-bootstrap';
-import { LinkContainer } from 'react-router-bootstrap';
-import { useLocation } from 'react-router-dom';
-import { useTranslation } from 'react-i18next';
-
-import LanguageSwitcher from './LanguageSwitcher';
-import User from './User';
-import Icon from '../components/common/Icon';
-
-const Header = () => {
-       const { pathname } = useLocation();
-       const { t } = useTranslation();
-
-       return <Navbar id="header" bg="dark" expand="md" variant="dark">
-               <Container fluid>
-                       <LinkContainer to="/">
-                               <Navbar.Brand>
-                                       ALttP
-                               </Navbar.Brand>
-                       </LinkContainer>
-                       <Navbar.Toggle aria-controls="header-nav" label={t('button.menu')}>
-                               <Icon.MENU title="" />
-                       </Navbar.Toggle>
-                       <Navbar.Collapse id="header-nav">
-                               <Nav activeKey={pathname}>
-                                       <LinkContainer to="/tournaments/6">
-                                               <Nav.Link href="/tournaments/6">
-                                                       ALttPR Weekly
-                                               </Nav.Link>
-                                       </LinkContainer>
-                               </Nav>
-                               <Nav activeKey={pathname} className="ms-auto">
-                                       <LinkContainer to="/tech">
-                                               <Nav.Link href="/tech">
-                                                       {t('menu.tech')}
-                                               </Nav.Link>
-                                       </LinkContainer>
-                                       <LinkContainer to="/map/lw">
-                                               <Nav.Link href="/map/lw">
-                                                       {t('menu.map')}
-                                               </Nav.Link>
-                                       </LinkContainer>
-                               </Nav>
-                               <div className="d-flex align-items-center">
-                                       <Navbar.Text className="mx-2">
-                                               <LanguageSwitcher />
-                                       </Navbar.Text>
-                                       <User />
-                               </div>
-                       </Navbar.Collapse>
-               </Container>
-       </Navbar>;
-};
-
-export default Header;
diff --git a/resources/js/app/Header.jsx b/resources/js/app/Header.jsx
new file mode 100644 (file)
index 0000000..b12682b
--- /dev/null
@@ -0,0 +1,61 @@
+import React from 'react';
+import { Container, Nav, Navbar } from 'react-bootstrap';
+import { LinkContainer } from 'react-router-bootstrap';
+import { useLocation } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
+
+import LanguageSwitcher from './LanguageSwitcher';
+import User from './User';
+import Icon from '../components/common/Icon';
+
+const Header = () => {
+       const { pathname } = useLocation();
+       const { t } = useTranslation();
+
+       return <Navbar id="header" bg="dark" expand="md" variant="dark">
+               <Container fluid>
+                       <LinkContainer to="/">
+                               <Navbar.Brand>
+                                       ALttP
+                               </Navbar.Brand>
+                       </LinkContainer>
+                       <Navbar.Toggle aria-controls="header-nav" label={t('button.menu')}>
+                               <Icon.MENU title="" />
+                       </Navbar.Toggle>
+                       <Navbar.Collapse id="header-nav">
+                               <Nav activeKey={pathname}>
+                                       <LinkContainer to="/tournaments/6">
+                                               <Nav.Link href="/tournaments/6">
+                                                       {t('menu.sdw')}
+                                               </Nav.Link>
+                                       </LinkContainer>
+                                       <LinkContainer to="/tournaments/7">
+                                               <Nav.Link href="/tournaments/7">
+                                                       {t('menu.circus')}
+                                               </Nav.Link>
+                                       </LinkContainer>
+                               </Nav>
+                               <Nav activeKey={pathname} className="ms-auto">
+                                       <LinkContainer to="/tech">
+                                               <Nav.Link href="/tech">
+                                                       {t('menu.tech')}
+                                               </Nav.Link>
+                                       </LinkContainer>
+                                       <LinkContainer to="/map/lw">
+                                               <Nav.Link href="/map/lw">
+                                                       {t('menu.map')}
+                                               </Nav.Link>
+                                       </LinkContainer>
+                               </Nav>
+                               <div className="d-flex align-items-center">
+                                       <Navbar.Text className="mx-2">
+                                               <LanguageSwitcher />
+                                       </Navbar.Text>
+                                       <User />
+                               </div>
+                       </Navbar.Collapse>
+               </Container>
+       </Navbar>;
+};
+
+export default Header;
diff --git a/resources/js/app/LanguageSwitcher.js b/resources/js/app/LanguageSwitcher.js
deleted file mode 100644 (file)
index 52efaf5..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import axios from 'axios';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import Icon from '../components/common/Icon';
-import { useUser } from '../hooks/user';
-import i18n from '../i18n';
-
-const setLanguage = (user, language) => {
-       i18n.changeLanguage(language);
-       if (user) {
-               axios.post('/api/users/set-language', { language });
-       }
-};
-
-const LanguageSwitcher = () => {
-       const { user } = useUser();
-
-       return <Button
-               className="text-reset"
-               href={`?lng=${i18n.language === 'de' ? 'en' : 'de'}`}
-               onClick={e => {
-                       setLanguage(user, i18n.language === 'de' ? 'en' : 'de');
-                       e.preventDefault();
-               }}
-               title={i18n.language === 'de' ? 'Switch to english' : 'Auf deutsch wechseln'}
-               variant="outline-secondary"
-       >
-               <Icon.LANGUAGE />
-               {' '}
-               {i18n.language === 'de' ? 'Deutsch' : 'English'}
-       </Button>;
-};
-
-export default withTranslation()(LanguageSwitcher);
diff --git a/resources/js/app/LanguageSwitcher.jsx b/resources/js/app/LanguageSwitcher.jsx
new file mode 100644 (file)
index 0000000..52efaf5
--- /dev/null
@@ -0,0 +1,36 @@
+import axios from 'axios';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import Icon from '../components/common/Icon';
+import { useUser } from '../hooks/user';
+import i18n from '../i18n';
+
+const setLanguage = (user, language) => {
+       i18n.changeLanguage(language);
+       if (user) {
+               axios.post('/api/users/set-language', { language });
+       }
+};
+
+const LanguageSwitcher = () => {
+       const { user } = useUser();
+
+       return <Button
+               className="text-reset"
+               href={`?lng=${i18n.language === 'de' ? 'en' : 'de'}`}
+               onClick={e => {
+                       setLanguage(user, i18n.language === 'de' ? 'en' : 'de');
+                       e.preventDefault();
+               }}
+               title={i18n.language === 'de' ? 'Switch to english' : 'Auf deutsch wechseln'}
+               variant="outline-secondary"
+       >
+               <Icon.LANGUAGE />
+               {' '}
+               {i18n.language === 'de' ? 'Deutsch' : 'English'}
+       </Button>;
+};
+
+export default withTranslation()(LanguageSwitcher);
diff --git a/resources/js/app/PrivacyDialog.js b/resources/js/app/PrivacyDialog.js
deleted file mode 100644 (file)
index 9cf96b3..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Modal } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-const PrivacyDialog = ({
-       onHide,
-       show,
-}) => {
-       const { t } = useTranslation();
-
-       return <Modal onHide={onHide} show={show}>
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {t('privacy.heading')}
-                       </Modal.Title>
-               </Modal.Header>
-               <Modal.Body>
-                       <p>{t('privacy.p1')}</p>
-                       <p>{t('privacy.p2')}</p>
-                       <p>{t('privacy.p3')}</p>
-               </Modal.Body>
-               <Modal.Footer>
-                       <Button onClick={onHide} variant="secondary">
-                               {t('button.close')}
-                       </Button>
-               </Modal.Footer>
-       </Modal>;
-};
-
-PrivacyDialog.propTypes = {
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-};
-
-export default PrivacyDialog;
diff --git a/resources/js/app/PrivacyDialog.jsx b/resources/js/app/PrivacyDialog.jsx
new file mode 100644 (file)
index 0000000..9cf96b3
--- /dev/null
@@ -0,0 +1,36 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const PrivacyDialog = ({
+       onHide,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('privacy.heading')}
+                       </Modal.Title>
+               </Modal.Header>
+               <Modal.Body>
+                       <p>{t('privacy.p1')}</p>
+                       <p>{t('privacy.p2')}</p>
+                       <p>{t('privacy.p3')}</p>
+               </Modal.Body>
+               <Modal.Footer>
+                       <Button onClick={onHide} variant="secondary">
+                               {t('button.close')}
+                       </Button>
+               </Modal.Footer>
+       </Modal>;
+};
+
+PrivacyDialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+};
+
+export default PrivacyDialog;
diff --git a/resources/js/app/Routes.js b/resources/js/app/Routes.js
deleted file mode 100644 (file)
index 0e35ddb..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-import React from 'react';
-import {
-       createBrowserRouter,
-       createRoutesFromElements,
-       Navigate,
-       Route,
-       RouterProvider,
-} from 'react-router-dom';
-
-import FullLayout from './FullLayout';
-import Front from '../pages/Front';
-import Technique from '../pages/Technique';
-import Techniques from '../pages/Techniques';
-import User from '../pages/User';
-
-const router = createBrowserRouter(
-       createRoutesFromElements(
-               <Route>
-                       <Route element={<FullLayout />}>
-                               <Route
-                                       path="discord-bot"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "admin" */
-                                               '../pages/DiscordBot'
-                                       )}
-                               />
-                               <Route
-                                       path="dungeons"
-                                       element={<Techniques namespace="dungeons" type="dungeon" />}
-                               />
-                               <Route
-                                       path="dungeons/:name"
-                                       element={<Technique basepath="dungeons" type="dungeon" />}
-                               />
-                               <Route
-                                       path="events"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "events" */
-                                               '../pages/Events'
-                                       )}
-                               />
-                               <Route
-                                       path="events/:name"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "events" */
-                                               '../pages/Event'
-                                       )}
-                               />
-                               <Route
-                                       path="h/:hash"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "seeds" */
-                                               '../pages/AlttpSeed'
-                                       )}
-                               />
-                               <Route
-                                       path="locations"
-                                       element={<Techniques namespace="locations" type="location" />}
-                               />
-                               <Route
-                                       path="locations/:name"
-                                       element={<Technique basepath="locations" type="location" />}
-                               />
-                               <Route path="map">
-                                       <Route index element={<Navigate replace to="lw" />} />
-                                       <Route
-                                               path=":activeMap"
-                                               lazy={() => import(
-                                                       /* webpackChunkName: "map" */
-                                                       '../pages/Map'
-                                               )}
-                                       />
-                               </Route>
-                               <Route
-                                       path="modes"
-                                       element={<Techniques namespace="modes" type="mode" />}
-                               />
-                               <Route
-                                       path="modes/:name"
-                                       element={<Technique basepath="modes" type="mode" />}
-                               />
-                               <Route
-                                       path="rulesets"
-                                       element={<Techniques namespace="rulesets" type="ruleset" />}
-                                       />
-                               <Route
-                                       path="rulesets/:name"
-                                       element={<Technique basepath="rulesets" type="ruleset" />}
-                               />
-                               <Route
-                                       path="schedule"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "events" */
-                                               '../pages/Schedule'
-                                       )}
-                               />
-                               <Route
-                                       path="tech"
-                                       element={<Techniques namespace="techniques" type="tech" />}
-                               />
-                               <Route
-                                       path="tech/:name"
-                                       element={<Technique basepath="tech" type="tech" />}
-                               />
-                               <Route
-                                       path="tournaments/:id"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "tournament" */
-                                               '../pages/Tournament'
-                                       )}
-                               />
-                               <Route
-                                       path="twitch-bot"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "admin" */
-                                               '../pages/TwitchBot'
-                                       )}
-                               />
-                               <Route
-                                       path="twitch-legal"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "twitch" */
-                                               '../pages/TwitchLegal'
-                                       )}
-                               />
-                               <Route path="users/:id" element={<User />} />
-                               <Route path="/" element={<Front />} />
-                               <Route path="*" element={<Navigate to="/" />} />
-                       </Route>
-                       <Route
-                               path="doors-tracker"
-                               lazy={() => import(
-                                       /* webpackChunkName: "tracker" */
-                                       '../pages/DoorsTracker'
-                               )}
-                       />
-                       <Route path="guessing-game">
-                               <Route
-                                       path="controls/:channelId?"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "guessing" */
-                                               '../pages/GuessingGameControls'
-                                       )}
-                               />
-                               <Route
-                                       path="monitor/:key"
-                                       lazy={() => import(
-                                               /* webpackChunkName: "guessing" */
-                                               '../pages/GuessingGameMonitor'
-                                       )}
-                               />
-                       </Route>
-                       <Route
-                               path="tracker"
-                               lazy={() => import(
-                                       /* webpackChunkName: "tracker" */
-                                       '../pages/Tracker'
-                               )}
-                       />
-               </Route>
-       )
-);
-
-const AppRoutes = () => <RouterProvider router={router} />;
-
-export default AppRoutes;
diff --git a/resources/js/app/Routes.jsx b/resources/js/app/Routes.jsx
new file mode 100644 (file)
index 0000000..abfeee4
--- /dev/null
@@ -0,0 +1,180 @@
+import React from 'react';
+import {
+       createBrowserRouter,
+       createRoutesFromElements,
+       Navigate,
+       Route,
+       RouterProvider,
+} from 'react-router-dom';
+
+import FullLayout from './FullLayout';
+import Front from '../pages/Front';
+import Technique from '../pages/Technique';
+import Techniques from '../pages/Techniques';
+import User from '../pages/User';
+
+const router = createBrowserRouter(
+       createRoutesFromElements(
+               <Route>
+                       <Route element={<FullLayout />}>
+                               <Route
+                                       path="discord-bot"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "admin" */
+                                               '../pages/DiscordBot'
+                                       )}
+                               />
+                               <Route
+                                       path="dungeons"
+                                       element={<Techniques namespace="dungeons" type="dungeon" />}
+                               />
+                               <Route
+                                       path="dungeons/:name"
+                                       element={<Technique basepath="dungeons" type="dungeon" />}
+                               />
+                               <Route
+                                       path="events"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "events" */
+                                               '../pages/Events'
+                                       )}
+                               />
+                               <Route
+                                       path="events/:name"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "events" */
+                                               '../pages/Event'
+                                       )}
+                               />
+                               <Route
+                                       path="h/:hash"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "seeds" */
+                                               '../pages/AlttpSeed'
+                                       )}
+                               />
+                               <Route
+                                       path="horstielog"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "horstie" */
+                                               '../pages/HorstieLog'
+                                       )}
+                               />
+                               <Route
+                                       path="locations"
+                                       element={<Techniques namespace="locations" type="location" />}
+                               />
+                               <Route
+                                       path="locations/:name"
+                                       element={<Technique basepath="locations" type="location" />}
+                               />
+                               <Route path="map">
+                                       <Route index element={<Navigate replace to="lw" />} />
+                                       <Route
+                                               path=":activeMap"
+                                               lazy={() => import(
+                                                       /* webpackChunkName: "map" */
+                                                       '../pages/Map'
+                                               )}
+                                       />
+                               </Route>
+                               <Route
+                                       path="modes"
+                                       element={<Techniques namespace="modes" type="mode" />}
+                               />
+                               <Route
+                                       path="modes/:name"
+                                       element={<Technique basepath="modes" type="mode" />}
+                               />
+                               <Route
+                                       path="rulesets"
+                                       element={<Techniques namespace="rulesets" type="ruleset" />}
+                                       />
+                               <Route
+                                       path="rulesets/:name"
+                                       element={<Technique basepath="rulesets" type="ruleset" />}
+                               />
+                               <Route
+                                       path="schedule"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "events" */
+                                               '../pages/Schedule'
+                                       )}
+                               />
+                               <Route
+                                       path="tech"
+                                       element={<Techniques namespace="techniques" type="tech" />}
+                               />
+                               <Route
+                                       path="tech/:name"
+                                       element={<Technique basepath="tech" type="tech" />}
+                               />
+                               <Route
+                                       path="tournaments/:id"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "tournament" */
+                                               '../pages/Tournament'
+                                       )}
+                               />
+                               <Route
+                                       path="twitch-bot"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "admin" */
+                                               '../pages/TwitchBot'
+                                       )}
+                               />
+                               <Route
+                                       path="twitch-legal"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "twitch" */
+                                               '../pages/TwitchLegal'
+                                       )}
+                               />
+                               <Route path="users/:id" element={<User />} />
+                               <Route path="/" element={<Front />} />
+                               <Route path="*" element={<Navigate to="/" />} />
+                       </Route>
+                       <Route
+                               path="doors-tracker"
+                               lazy={() => import(
+                                       /* webpackChunkName: "tracker" */
+                                       '../pages/DoorsTracker'
+                               )}
+                       />
+                       <Route path="guessing-game">
+                               <Route
+                                       path="controls/:channelId?"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "guessing" */
+                                               '../pages/GuessingGameControls'
+                                       )}
+                               />
+                               <Route
+                                       path="monitor/:key"
+                                       lazy={() => import(
+                                               /* webpackChunkName: "guessing" */
+                                               '../pages/GuessingGameMonitor'
+                                       )}
+                               />
+                       </Route>
+                       <Route
+                               path="tracker"
+                               lazy={() => import(
+                                       /* webpackChunkName: "tracker" */
+                                       '../pages/Tracker'
+                               )}
+                       />
+                       <Route
+                               path="zootr-mixed-pools-tracker"
+                               lazy={() => import(
+                                       /* webpackChunkName: "zootr" */
+                                       '../pages/ZootrMixedPoolsTracker'
+                               )}
+                       />
+               </Route>
+       )
+);
+
+const AppRoutes = () => <RouterProvider router={router} />;
+
+export default AppRoutes;
diff --git a/resources/js/app/User.js b/resources/js/app/User.js
deleted file mode 100644 (file)
index 402178a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import { Button, Nav } from 'react-bootstrap';
-import { LinkContainer } from 'react-router-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from '../components/common/Icon';
-import { useUser } from '../hooks/user';
-import { getAvatarUrl } from '../helpers/User';
-
-const User = () => {
-       const { t } = useTranslation();
-       const { logout, user } = useUser();
-
-       return user
-               ? <>
-                       <Nav className="ms-auto">
-                               <LinkContainer to={`/users/${user.id}`}>
-                                       <Nav.Link>
-                                               <img alt="" src={getAvatarUrl(user)} />
-                                               {user.username}
-                                               {user.discriminator && user.discriminator !== '0' ?
-                                                       <span className="text-muted">#{user.discriminator}</span>
-                                               : null}
-                                       </Nav.Link>
-                               </LinkContainer>
-                       </Nav>
-                       <Button
-                       className="ms-2"
-                               onClick={logout}
-                               title={t('button.logout')}
-                               variant="outline-secondary"
-                       >
-                               <Icon.LOGOUT title="" />
-                       </Button>
-               </>
-               : <Button
-                       className="ms-auto"
-                       href="/login"
-                       onClick={() => {
-                               if (location.pathname.length > 1) {
-                                       localStorage.setItem('returnPath', location.pathname.substr(1));
-                               }
-                       }}
-                       title={t('button.login')}
-                       variant="discord"
-               >
-                       <Icon.DISCORD />
-                       {' '}
-                       {t('button.login')}
-               </Button>;
-};
-
-export default User;
diff --git a/resources/js/app/User.jsx b/resources/js/app/User.jsx
new file mode 100644 (file)
index 0000000..0b6f098
--- /dev/null
@@ -0,0 +1,53 @@
+import React from 'react';
+import { Button, Nav } from 'react-bootstrap';
+import { LinkContainer } from 'react-router-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../components/common/Icon';
+import { useUser } from '../hooks/user';
+import { getAvatarUrl } from '../helpers/User';
+
+const User = () => {
+       const { t } = useTranslation();
+       const { logout, user } = useUser();
+
+       return user
+               ? <>
+                       <Nav className="ms-auto">
+                               <LinkContainer to={`/users/${user.username}`}>
+                                       <Nav.Link>
+                                               <img alt="" src={getAvatarUrl(user)} />
+                                               {user.username}
+                                               {user.discriminator && user.discriminator !== '0' ?
+                                                       <span className="text-muted">#{user.discriminator}</span>
+                                               : null}
+                                       </Nav.Link>
+                               </LinkContainer>
+                       </Nav>
+                       <Button
+                               className="ms-2"
+                               onClick={logout}
+                               title={t('button.logout')}
+                               variant="outline-secondary"
+                       >
+                               <Icon.LOGOUT title="" />
+                       </Button>
+               </>
+               : <Button
+                       className="ms-auto"
+                       href="/login"
+                       onClick={() => {
+                               if (location.pathname.length > 1) {
+                                       localStorage.setItem('returnPath', location.pathname.substr(1));
+                               }
+                       }}
+                       title={t('button.login')}
+                       variant="discord"
+               >
+                       <Icon.DISCORD />
+                       {' '}
+                       {t('button.login')}
+               </Button>;
+};
+
+export default User;
diff --git a/resources/js/app/index.js b/resources/js/app/index.js
deleted file mode 100644 (file)
index 385ed7d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-
-import Routes from './Routes';
-import AlttpBaseRomProvider from '../helpers/AlttpBaseRomContext';
-import { SNESProvider } from '../hooks/snes';
-import { UserProvider } from '../hooks/user';
-import i18n from '../i18n';
-
-const App = () => {
-       const { t } = useTranslation();
-
-       React.useEffect(() => {
-               window.Echo.channel('App.Control')
-                       .listen('PleaseRefresh', () => {
-                               location.reload();
-                       });
-               return () => {
-                       window.Echo.leave('App.Control');
-               };
-       }, []);
-
-       return <AlttpBaseRomProvider>
-               <SNESProvider>
-                       <UserProvider>
-                               <Helmet>
-                                       <html lang={i18n.language} />
-                                       <title>{t('general.appName')}</title>
-                                       <meta name="description" content={t('general.appDescription')} />
-                               </Helmet>
-                               <Routes />
-                       </UserProvider>
-               </SNESProvider>
-       </AlttpBaseRomProvider>;
-};
-
-export default App;
diff --git a/resources/js/app/index.jsx b/resources/js/app/index.jsx
new file mode 100644 (file)
index 0000000..385ed7d
--- /dev/null
@@ -0,0 +1,38 @@
+import React from 'react';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+
+import Routes from './Routes';
+import AlttpBaseRomProvider from '../helpers/AlttpBaseRomContext';
+import { SNESProvider } from '../hooks/snes';
+import { UserProvider } from '../hooks/user';
+import i18n from '../i18n';
+
+const App = () => {
+       const { t } = useTranslation();
+
+       React.useEffect(() => {
+               window.Echo.channel('App.Control')
+                       .listen('PleaseRefresh', () => {
+                               location.reload();
+                       });
+               return () => {
+                       window.Echo.leave('App.Control');
+               };
+       }, []);
+
+       return <AlttpBaseRomProvider>
+               <SNESProvider>
+                       <UserProvider>
+                               <Helmet>
+                                       <html lang={i18n.language} />
+                                       <title>{t('general.appName')}</title>
+                                       <meta name="description" content={t('general.appDescription')} />
+                               </Helmet>
+                               <Routes />
+                       </UserProvider>
+               </SNESProvider>
+       </AlttpBaseRomProvider>;
+};
+
+export default App;
index cffa4cb5770b27615eb910c235faa0132b7943dc..0ed0904e17edb549e1d3c6e3f018b0628b526f3a 100644 (file)
@@ -1,10 +1,7 @@
-window._ = require('lodash');
-
-try {
-    require('bootstrap');
-} catch (e) {
-       // well...
-}
+import axios from 'axios';
+import Echo from 'laravel-echo';
+import Pusher from 'pusher-js';
+import qs from 'qs';
 
 /**
  * We'll load the axios HTTP library which allows us to easily issue requests
 
 /**
  * We'll load the axios HTTP library which allows us to easily issue requests
@@ -12,11 +9,8 @@ try {
  * CSRF token as a header based on the value of the "XSRF" token cookie.
  */
 
  * CSRF token as a header based on the value of the "XSRF" token cookie.
  */
 
-window.axios = require('axios');
-
+window.axios = axios;
 window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
 window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
-
-import qs from 'qs';
 window.axios.defaults.paramsSerializer = p => qs.stringify(p, { arrayFormat: 'brackets' });
 
 /**
 window.axios.defaults.paramsSerializer = p => qs.stringify(p, { arrayFormat: 'brackets' });
 
 /**
@@ -25,14 +19,11 @@ window.axios.defaults.paramsSerializer = p => qs.stringify(p, { arrayFormat: 'br
  * allows your team to easily build robust real-time web applications.
  */
 
  * allows your team to easily build robust real-time web applications.
  */
 
-import Echo from 'laravel-echo';
-
-window.Pusher = require('pusher-js');
+window.Pusher = Pusher;
 
 window.Echo = new Echo({
 
 window.Echo = new Echo({
-    broadcaster: 'pusher',
-    key: process.env.MIX_PUSHER_APP_KEY,
-    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
+    broadcaster: 'reverb',
+    key: import.meta.env.VITE_REVERB_APP_KEY,
     wsHost: window.location.hostname,
     wsPort: window.location.port,
     forceTLS: false,
     wsHost: window.location.hostname,
     wsPort: window.location.port,
     forceTLS: false,
diff --git a/resources/js/components/alttp-seeds/BaseRomButton.js b/resources/js/components/alttp-seeds/BaseRomButton.js
deleted file mode 100644 (file)
index e8954d5..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import i18n from '../../i18n';
-
-import { useAlttpBaseRom } from '../../helpers/AlttpBaseRomContext';
-
-const BaseRomButton = () => {
-       const { rom, setRom } = useAlttpBaseRom();
-
-       const handleFile = React.useCallback(async e => {
-               if (e.target.files.length != 1) {
-                       setRom(null);
-               } else {
-                       const buf = await e.target.files[0].arrayBuffer();
-                       setRom(buf);
-               }
-       }, [setRom]);
-
-       if (rom) return null;
-
-       return <span>
-               <input
-                       accept=".sfc"
-                       className="d-none"
-                       id="alttp.baseRom"
-                       onChange={handleFile}
-                       type="file"
-               />
-               <label htmlFor="alttp.baseRom">
-                       <Button as="span" variant="primary">
-                               {i18n.t('alttp.setBaseRom')}
-                       </Button>
-               </label>
-       </span>;
-};
-
-export default withTranslation()(BaseRomButton);
diff --git a/resources/js/components/alttp-seeds/BaseRomButton.jsx b/resources/js/components/alttp-seeds/BaseRomButton.jsx
new file mode 100644 (file)
index 0000000..e8954d5
--- /dev/null
@@ -0,0 +1,39 @@
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import i18n from '../../i18n';
+
+import { useAlttpBaseRom } from '../../helpers/AlttpBaseRomContext';
+
+const BaseRomButton = () => {
+       const { rom, setRom } = useAlttpBaseRom();
+
+       const handleFile = React.useCallback(async e => {
+               if (e.target.files.length != 1) {
+                       setRom(null);
+               } else {
+                       const buf = await e.target.files[0].arrayBuffer();
+                       setRom(buf);
+               }
+       }, [setRom]);
+
+       if (rom) return null;
+
+       return <span>
+               <input
+                       accept=".sfc"
+                       className="d-none"
+                       id="alttp.baseRom"
+                       onChange={handleFile}
+                       type="file"
+               />
+               <label htmlFor="alttp.baseRom">
+                       <Button as="span" variant="primary">
+                               {i18n.t('alttp.setBaseRom')}
+                       </Button>
+               </label>
+       </span>;
+};
+
+export default withTranslation()(BaseRomButton);
diff --git a/resources/js/components/alttp-seeds/Seed.js b/resources/js/components/alttp-seeds/Seed.js
deleted file mode 100644 (file)
index e804ae3..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-import FileSaver from 'file-saver';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Container, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import BaseRomButton from './BaseRomButton';
-import { useAlttpBaseRom } from '../../helpers/AlttpBaseRomContext';
-import BPS from '../../helpers/bps';
-import i18n from '../../i18n';
-
-const applyPatch = (rom, patch, filename) => {
-       try {
-               const bps = new BPS();
-               bps.setPatch(patch);
-               bps.setSource(rom);
-               const result = bps.applyPatch();
-               FileSaver.saveAs(new Blob([result], { type: 'application/octet-stream' }), filename);
-       } catch (e) {
-               toastr.error(i18n.t('alttpSeeds.patchError', { msg: e.message }));
-       }
-};
-
-const isDefaultSetting = () => false;
-
-const Seed = ({ onRetry, patch, seed }) => {
-       const { rom } = useAlttpBaseRom();
-
-       return <Container>
-               <h1>{i18n.t('alttpSeeds.heading')}</h1>
-               <Row>
-                       <Col md={{ order: 2 }}>
-                               {rom ?
-                                       <Button
-                                               disabled={!seed || seed.status !== 'generated' || !patch}
-                                               onClick={() => applyPatch(
-                                                       rom,
-                                                       patch,
-                                                       `${i18n.t('alttpSeeds.filename', {
-                                                               hash: seed.hash,
-                                                               preset: seed.preset,
-                                                       })}.sfc`,
-                                               )}
-                                               variant="primary"
-                                       >
-                                               {i18n.t(patch ? 'alttpSeeds.patch' : 'alttpSeeds.fetchingPatch')}
-                                       </Button>
-                               :
-                                       <BaseRomButton />
-                               }
-                       </Col>
-                       <Col md={{ order: 1 }}>
-                               <p>
-                                       {i18n.t('alttpSeeds.preset')}:
-                                       {' '}
-                                       <strong>{i18n.t(`alttpSeeds.presets.${seed.preset}`)}</strong>
-                               </p>
-                               {seed.seed ?
-                                       <p>
-                                               {i18n.t('alttpSeeds.seed')}:
-                                               {' '}
-                                               <strong>{seed.seed}</strong>
-                                       </p>
-                               : null}
-                               {seed.race ?
-                                       <p>{i18n.t('alttpSeeds.race')}</p>
-                               : null}
-                               {seed.mystery ?
-                                       <p>{i18n.t('alttpSeeds.mystery')}</p>
-                               : null}
-                               {seed.status === 'generated' ?
-                                       <p>
-                                               {i18n.t('alttpSeeds.generated')}:
-                                               {' '}
-                                               <strong>
-                                                       {i18n.t('alttpSeeds.date', { date: new Date(seed.updated_at) })}
-                                               </strong>
-                                       </p>
-                               :
-                                       <p>
-                                               {i18n.t('alttpSeeds.status')}:
-                                               {' '}
-                                               <strong>{i18n.t(`alttpSeeds.statuses.${seed.status}`)}</strong>
-                                       </p>
-                               }
-                               {seed.status === 'error' ?
-                                       <p>
-                                               <Button
-                                                       onClick={onRetry}
-                                                       variant="secondary"
-                                               >
-                                                       {i18n.t('button.retry')}
-                                               </Button>
-                                       </p>
-                               : null}
-                       </Col>
-               </Row>
-               <h2 className="mt-5">{i18n.t('alttpSeeds.generator')}</h2>
-               <p>{i18n.t(`alttpSeeds.generators.${seed.generator}`)}</p>
-               {seed.settings ? <>
-                       <h2 className="mt-5">{i18n.t('alttpSeeds.settings')}</h2>
-                       <Row>
-                               {Object.entries(seed.settings).map(([key, value]) =>
-                                       <Col key={key} sm={4} md={3} lg={2} className="mb-2">
-                                               <small className="text-muted">
-                                                       {i18n.t(`alttpSeeds.settingName.${key}`)}
-                                               </small>
-                                               <br />
-                                               {isDefaultSetting(key, value) ?
-                                                       i18n.t(`alttpSeeds.settingValue.${key}.${value}`)
-                                               :
-                                                       <strong>{i18n.t(`alttpSeeds.settingValue.${key}.${value}`)}</strong>
-                                               }
-                                       </Col>
-                               )}
-                       </Row>
-               </> : null}
-       </Container>;
-};
-
-Seed.propTypes = {
-       onRetry: PropTypes.func,
-       patch: PropTypes.instanceOf(ArrayBuffer),
-       seed: PropTypes.shape({
-               generator: PropTypes.string,
-               hash: PropTypes.string,
-               mystery: PropTypes.bool,
-               preset: PropTypes.string,
-               race: PropTypes.bool,
-               seed: PropTypes.string,
-               settings: PropTypes.shape({
-               }),
-               status: PropTypes.string,
-               updated_at: PropTypes.string,
-       }),
-};
-
-export default withTranslation()(Seed);
diff --git a/resources/js/components/alttp-seeds/Seed.jsx b/resources/js/components/alttp-seeds/Seed.jsx
new file mode 100644 (file)
index 0000000..e804ae3
--- /dev/null
@@ -0,0 +1,139 @@
+import FileSaver from 'file-saver';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Container, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import BaseRomButton from './BaseRomButton';
+import { useAlttpBaseRom } from '../../helpers/AlttpBaseRomContext';
+import BPS from '../../helpers/bps';
+import i18n from '../../i18n';
+
+const applyPatch = (rom, patch, filename) => {
+       try {
+               const bps = new BPS();
+               bps.setPatch(patch);
+               bps.setSource(rom);
+               const result = bps.applyPatch();
+               FileSaver.saveAs(new Blob([result], { type: 'application/octet-stream' }), filename);
+       } catch (e) {
+               toastr.error(i18n.t('alttpSeeds.patchError', { msg: e.message }));
+       }
+};
+
+const isDefaultSetting = () => false;
+
+const Seed = ({ onRetry, patch, seed }) => {
+       const { rom } = useAlttpBaseRom();
+
+       return <Container>
+               <h1>{i18n.t('alttpSeeds.heading')}</h1>
+               <Row>
+                       <Col md={{ order: 2 }}>
+                               {rom ?
+                                       <Button
+                                               disabled={!seed || seed.status !== 'generated' || !patch}
+                                               onClick={() => applyPatch(
+                                                       rom,
+                                                       patch,
+                                                       `${i18n.t('alttpSeeds.filename', {
+                                                               hash: seed.hash,
+                                                               preset: seed.preset,
+                                                       })}.sfc`,
+                                               )}
+                                               variant="primary"
+                                       >
+                                               {i18n.t(patch ? 'alttpSeeds.patch' : 'alttpSeeds.fetchingPatch')}
+                                       </Button>
+                               :
+                                       <BaseRomButton />
+                               }
+                       </Col>
+                       <Col md={{ order: 1 }}>
+                               <p>
+                                       {i18n.t('alttpSeeds.preset')}:
+                                       {' '}
+                                       <strong>{i18n.t(`alttpSeeds.presets.${seed.preset}`)}</strong>
+                               </p>
+                               {seed.seed ?
+                                       <p>
+                                               {i18n.t('alttpSeeds.seed')}:
+                                               {' '}
+                                               <strong>{seed.seed}</strong>
+                                       </p>
+                               : null}
+                               {seed.race ?
+                                       <p>{i18n.t('alttpSeeds.race')}</p>
+                               : null}
+                               {seed.mystery ?
+                                       <p>{i18n.t('alttpSeeds.mystery')}</p>
+                               : null}
+                               {seed.status === 'generated' ?
+                                       <p>
+                                               {i18n.t('alttpSeeds.generated')}:
+                                               {' '}
+                                               <strong>
+                                                       {i18n.t('alttpSeeds.date', { date: new Date(seed.updated_at) })}
+                                               </strong>
+                                       </p>
+                               :
+                                       <p>
+                                               {i18n.t('alttpSeeds.status')}:
+                                               {' '}
+                                               <strong>{i18n.t(`alttpSeeds.statuses.${seed.status}`)}</strong>
+                                       </p>
+                               }
+                               {seed.status === 'error' ?
+                                       <p>
+                                               <Button
+                                                       onClick={onRetry}
+                                                       variant="secondary"
+                                               >
+                                                       {i18n.t('button.retry')}
+                                               </Button>
+                                       </p>
+                               : null}
+                       </Col>
+               </Row>
+               <h2 className="mt-5">{i18n.t('alttpSeeds.generator')}</h2>
+               <p>{i18n.t(`alttpSeeds.generators.${seed.generator}`)}</p>
+               {seed.settings ? <>
+                       <h2 className="mt-5">{i18n.t('alttpSeeds.settings')}</h2>
+                       <Row>
+                               {Object.entries(seed.settings).map(([key, value]) =>
+                                       <Col key={key} sm={4} md={3} lg={2} className="mb-2">
+                                               <small className="text-muted">
+                                                       {i18n.t(`alttpSeeds.settingName.${key}`)}
+                                               </small>
+                                               <br />
+                                               {isDefaultSetting(key, value) ?
+                                                       i18n.t(`alttpSeeds.settingValue.${key}.${value}`)
+                                               :
+                                                       <strong>{i18n.t(`alttpSeeds.settingValue.${key}.${value}`)}</strong>
+                                               }
+                                       </Col>
+                               )}
+                       </Row>
+               </> : null}
+       </Container>;
+};
+
+Seed.propTypes = {
+       onRetry: PropTypes.func,
+       patch: PropTypes.instanceOf(ArrayBuffer),
+       seed: PropTypes.shape({
+               generator: PropTypes.string,
+               hash: PropTypes.string,
+               mystery: PropTypes.bool,
+               preset: PropTypes.string,
+               race: PropTypes.bool,
+               seed: PropTypes.string,
+               settings: PropTypes.shape({
+               }),
+               status: PropTypes.string,
+               updated_at: PropTypes.string,
+       }),
+};
+
+export default withTranslation()(Seed);
diff --git a/resources/js/components/applications/Button.js b/resources/js/components/applications/Button.js
deleted file mode 100644 (file)
index 2361b09..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Badge, Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Dialog from './Dialog';
-import Icon from '../common/Icon';
-import { mayHandleApplications } from '../../helpers/permissions';
-import { getPendingApplications } from '../../helpers/Tournament';
-import { useUser } from '../../hooks/user';
-
-const ApplicationsButton = ({ tournament }) => {
-       const [showDialog, setShowDialog] = React.useState(false);
-
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       if (!user || !tournament.accept_applications || !mayHandleApplications(user, tournament)) {
-               return null;
-       }
-
-       const pending = getPendingApplications(tournament);
-
-       return <>
-               <Button
-                       onClick={() => setShowDialog(true)}
-                       title={t('tournaments.applications')}
-                       variant="primary"
-               >
-                       <Icon.APPLICATIONS title="" />
-                       {pending.length ?
-                               <>
-                                       {' '}
-                                       <Badge>{pending.length}</Badge>
-                               </>
-                       : null}
-               </Button>
-               <Dialog
-                       onHide={() => setShowDialog(false)}
-                       show={showDialog}
-                       tournament={tournament}
-               />
-       </>;
-};
-
-ApplicationsButton.propTypes = {
-       tournament: PropTypes.shape({
-               accept_applications: PropTypes.bool,
-               id: PropTypes.number,
-       }),
-};
-
-export default ApplicationsButton;
diff --git a/resources/js/components/applications/Button.jsx b/resources/js/components/applications/Button.jsx
new file mode 100644 (file)
index 0000000..2361b09
--- /dev/null
@@ -0,0 +1,53 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Badge, Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Dialog from './Dialog';
+import Icon from '../common/Icon';
+import { mayHandleApplications } from '../../helpers/permissions';
+import { getPendingApplications } from '../../helpers/Tournament';
+import { useUser } from '../../hooks/user';
+
+const ApplicationsButton = ({ tournament }) => {
+       const [showDialog, setShowDialog] = React.useState(false);
+
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       if (!user || !tournament.accept_applications || !mayHandleApplications(user, tournament)) {
+               return null;
+       }
+
+       const pending = getPendingApplications(tournament);
+
+       return <>
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       title={t('tournaments.applications')}
+                       variant="primary"
+               >
+                       <Icon.APPLICATIONS title="" />
+                       {pending.length ?
+                               <>
+                                       {' '}
+                                       <Badge>{pending.length}</Badge>
+                               </>
+                       : null}
+               </Button>
+               <Dialog
+                       onHide={() => setShowDialog(false)}
+                       show={showDialog}
+                       tournament={tournament}
+               />
+       </>;
+};
+
+ApplicationsButton.propTypes = {
+       tournament: PropTypes.shape({
+               accept_applications: PropTypes.bool,
+               id: PropTypes.number,
+       }),
+};
+
+export default ApplicationsButton;
diff --git a/resources/js/components/applications/Dialog.js b/resources/js/components/applications/Dialog.js
deleted file mode 100644 (file)
index a42fb3d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Button, Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import List from './List';
-import i18n from '../../i18n';
-
-const Dialog = ({ onHide, show, tournament }) =>
-<Modal className="applications-dialog" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('tournaments.applications')}
-               </Modal.Title>
-       </Modal.Header>
-       <Modal.Body className="p-0">
-               {tournament.applications && tournament.applications.length ?
-                       <List tournament={tournament} />
-               :
-                       <Alert variant="info">
-                               {i18n.t('tournaments.noApplications')}
-                       </Alert>
-               }
-       </Modal.Body>
-       <Modal.Footer>
-               <Button onClick={onHide} variant="secondary">
-                       {i18n.t('button.close')}
-               </Button>
-       </Modal.Footer>
-</Modal>;
-
-Dialog.propTypes = {
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-       tournament: PropTypes.shape({
-               applications: PropTypes.arrayOf(PropTypes.shape({
-               }))
-       }),
-};
-
-export default withTranslation()(Dialog);
diff --git a/resources/js/components/applications/Dialog.jsx b/resources/js/components/applications/Dialog.jsx
new file mode 100644 (file)
index 0000000..a42fb3d
--- /dev/null
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import List from './List';
+import i18n from '../../i18n';
+
+const Dialog = ({ onHide, show, tournament }) =>
+<Modal className="applications-dialog" onHide={onHide} show={show}>
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t('tournaments.applications')}
+               </Modal.Title>
+       </Modal.Header>
+       <Modal.Body className="p-0">
+               {tournament.applications && tournament.applications.length ?
+                       <List tournament={tournament} />
+               :
+                       <Alert variant="info">
+                               {i18n.t('tournaments.noApplications')}
+                       </Alert>
+               }
+       </Modal.Body>
+       <Modal.Footer>
+               <Button onClick={onHide} variant="secondary">
+                       {i18n.t('button.close')}
+               </Button>
+       </Modal.Footer>
+</Modal>;
+
+Dialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+               applications: PropTypes.arrayOf(PropTypes.shape({
+               }))
+       }),
+};
+
+export default withTranslation()(Dialog);
diff --git a/resources/js/components/applications/Item.js b/resources/js/components/applications/Item.js
deleted file mode 100644 (file)
index 8f6aef1..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, ListGroup } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import Icon from '../common/Icon';
-import Box from '../users/Box';
-import i18n from '../../i18n';
-
-const accept = async (tournament, application) => {
-       try {
-               await axios.post(`/api/application/${application.id}/accept`);
-               toastr.success(i18n.t('applications.acceptSuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('applications.acceptError'));
-       }
-};
-
-const reject = async (tournament, application) => {
-       try {
-               await axios.post(`/api/application/${application.id}/reject`);
-               toastr.success(i18n.t('applications.rejectSuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('applications.rejectError'));
-       }
-};
-
-const Item = ({ application, tournament }) =>
-<ListGroup.Item className="d-flex justify-content-between align-items-center">
-       <Box discriminator user={application.user} />
-       <div className="button-bar">
-               <Button
-                       onClick={() => accept(tournament, application)}
-                       title={i18n.t('applications.accept')}
-                       variant="success"
-               >
-                       <Icon.ACCEPT title="" />
-               </Button>
-               <Button
-                       onClick={() => reject(tournament, application)}
-                       title={i18n.t('applications.reject')}
-                       variant="danger"
-               >
-                       <Icon.REJECT title="" />
-               </Button>
-       </div>
-</ListGroup.Item>;
-
-Item.propTypes = {
-       application: PropTypes.shape({
-               user: PropTypes.shape({
-               }),
-       }),
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(Item);
diff --git a/resources/js/components/applications/Item.jsx b/resources/js/components/applications/Item.jsx
new file mode 100644 (file)
index 0000000..8f6aef1
--- /dev/null
@@ -0,0 +1,60 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, ListGroup } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import Icon from '../common/Icon';
+import Box from '../users/Box';
+import i18n from '../../i18n';
+
+const accept = async (tournament, application) => {
+       try {
+               await axios.post(`/api/application/${application.id}/accept`);
+               toastr.success(i18n.t('applications.acceptSuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('applications.acceptError'));
+       }
+};
+
+const reject = async (tournament, application) => {
+       try {
+               await axios.post(`/api/application/${application.id}/reject`);
+               toastr.success(i18n.t('applications.rejectSuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('applications.rejectError'));
+       }
+};
+
+const Item = ({ application, tournament }) =>
+<ListGroup.Item className="d-flex justify-content-between align-items-center">
+       <Box discriminator user={application.user} />
+       <div className="button-bar">
+               <Button
+                       onClick={() => accept(tournament, application)}
+                       title={i18n.t('applications.accept')}
+                       variant="success"
+               >
+                       <Icon.ACCEPT title="" />
+               </Button>
+               <Button
+                       onClick={() => reject(tournament, application)}
+                       title={i18n.t('applications.reject')}
+                       variant="danger"
+               >
+                       <Icon.REJECT title="" />
+               </Button>
+       </div>
+</ListGroup.Item>;
+
+Item.propTypes = {
+       application: PropTypes.shape({
+               user: PropTypes.shape({
+               }),
+       }),
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(Item);
diff --git a/resources/js/components/applications/List.js b/resources/js/components/applications/List.js
deleted file mode 100644 (file)
index 6460be3..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { ListGroup } from 'react-bootstrap';
-
-import Item from './Item';
-
-const List = ({ tournament }) =>
-<ListGroup variant="flush">
-       {tournament.applications.map(application =>
-               <Item application={application} key={application.id} tournament={tournament} />
-       )}
-</ListGroup>;
-
-List.propTypes = {
-       tournament: PropTypes.shape({
-               applications: PropTypes.arrayOf(PropTypes.shape({
-               })),
-       }),
-};
-
-export default List;
diff --git a/resources/js/components/applications/List.jsx b/resources/js/components/applications/List.jsx
new file mode 100644 (file)
index 0000000..6460be3
--- /dev/null
@@ -0,0 +1,21 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { ListGroup } from 'react-bootstrap';
+
+import Item from './Item';
+
+const List = ({ tournament }) =>
+<ListGroup variant="flush">
+       {tournament.applications.map(application =>
+               <Item application={application} key={application.id} tournament={tournament} />
+       )}
+</ListGroup>;
+
+List.propTypes = {
+       tournament: PropTypes.shape({
+               applications: PropTypes.arrayOf(PropTypes.shape({
+               })),
+       }),
+};
+
+export default List;
diff --git a/resources/js/components/channel/Item.jsx b/resources/js/components/channel/Item.jsx
new file mode 100644 (file)
index 0000000..a2b712f
--- /dev/null
@@ -0,0 +1,45 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Icon from '../common/Icon';
+
+const Item = ({ channel }) => {
+       const classNames = [
+               'channel-item',
+               channel.twitch_live ? 'is-live' : 'not-live',
+       ];
+       return <a
+               className={classNames.join(' ')}
+               href={channel.stream_link}
+               rel="noreferrer"
+               target="_blank"
+       >
+               <div className="d-flex justify-content-between">
+                       <div className="channel-title fs-5">{channel.title}</div>
+                       {channel.twitch_live ?
+                               <div className="channel-viewers">
+                                       <Icon.STREAM />
+                                       {' '}
+                                       {channel.twitch_viewers}
+                               </div>
+                       : null}
+               </div>
+               <div className="channel-stream-title">{channel.twitch_title}</div>
+               <div className="channel-category text-muted">
+                       <small>{channel.twitch_category_name}</small>
+               </div>
+       </a>;
+};
+
+Item.propTypes = {
+       channel: PropTypes.shape({
+               stream_link: PropTypes.string,
+               title: PropTypes.string,
+               twitch_category_name: PropTypes.string,
+               twitch_live: PropTypes.bool,
+               twitch_title: PropTypes.string,
+               twitch_viewers: PropTypes.number,
+       }),
+};
+
+export default Item;
diff --git a/resources/js/components/channel/Link.jsx b/resources/js/components/channel/Link.jsx
new file mode 100644 (file)
index 0000000..3eeb7b9
--- /dev/null
@@ -0,0 +1,29 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+
+import Icon from '../common/Icon';
+
+const Link = ({ channel }) => {
+       return <Button
+               href={channel.stream_link}
+               rel="noreferrer"
+               target="_blank"
+               title={channel.title}
+               variant="outline-twitch"
+       >
+               <Icon.STREAM />
+               &nbsp;
+               {channel.short_name || channel.title}
+       </Button>;
+};
+
+Link.propTypes = {
+       channel: PropTypes.shape({
+               short_name: PropTypes.string,
+               stream_link: PropTypes.string,
+               title: PropTypes.string,
+       }),
+};
+
+export default Link;
diff --git a/resources/js/components/channel/List.jsx b/resources/js/components/channel/List.jsx
new file mode 100644 (file)
index 0000000..c1c4d41
--- /dev/null
@@ -0,0 +1,19 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Item from './Item';
+
+const List = ({ channels = [] }) => {
+       return <div className="channel-list">
+               {channels.map(channel =>
+                       <Item channel={channel} key={channel.id} />
+               )}
+       </div>;
+};
+
+List.propTypes = {
+       channels: PropTypes.arrayOf(PropTypes.shape({
+       })),
+};
+
+export default List;
diff --git a/resources/js/components/chat-bot-logs/ChatBotLog.js b/resources/js/components/chat-bot-logs/ChatBotLog.js
deleted file mode 100644 (file)
index 45c8027..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React, { useEffect, useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Dialog from './Dialog';
-import Icon from '../common/Icon';
-
-const ChatBotLog = ({ id }) => {
-       const [showDialog, setShowDialog] = useState(false);
-       const [log, setLog] = useState([]);
-
-       const { t } = useTranslation();
-
-       useEffect(() => {
-               if (!showDialog) return;
-               const ctrl = new AbortController();
-               axios
-                       .get(`/api/channels/${id}/chat-bot-log`, { signal: ctrl.signal })
-                       .then(response => {
-                               setLog(response.data);
-                       });
-               return () => {
-                       ctrl.abort();
-               };
-       }, [id, showDialog]);
-
-       return (
-               <>
-                       <Button
-                               onClick={() => setShowDialog(true)}
-                               title={t('button.protocol')}
-                               variant="outline-info"
-                       >
-                               <Icon.PROTOCOL title="" />
-                       </Button>
-                       <Dialog
-                               log={log}
-                               onHide={() => setShowDialog(false)}
-                               show={showDialog}
-                       />
-               </>
-       );
-};
-
-ChatBotLog.propTypes = {
-       id: PropTypes.number,
-};
-
-export default ChatBotLog;
diff --git a/resources/js/components/chat-bot-logs/ChatBotLog.jsx b/resources/js/components/chat-bot-logs/ChatBotLog.jsx
new file mode 100644 (file)
index 0000000..45c8027
--- /dev/null
@@ -0,0 +1,51 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React, { useEffect, useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Dialog from './Dialog';
+import Icon from '../common/Icon';
+
+const ChatBotLog = ({ id }) => {
+       const [showDialog, setShowDialog] = useState(false);
+       const [log, setLog] = useState([]);
+
+       const { t } = useTranslation();
+
+       useEffect(() => {
+               if (!showDialog) return;
+               const ctrl = new AbortController();
+               axios
+                       .get(`/api/channels/${id}/chat-bot-log`, { signal: ctrl.signal })
+                       .then(response => {
+                               setLog(response.data);
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [id, showDialog]);
+
+       return (
+               <>
+                       <Button
+                               onClick={() => setShowDialog(true)}
+                               title={t('button.protocol')}
+                               variant="outline-info"
+                       >
+                               <Icon.PROTOCOL title="" />
+                       </Button>
+                       <Dialog
+                               log={log}
+                               onHide={() => setShowDialog(false)}
+                               show={showDialog}
+                       />
+               </>
+       );
+};
+
+ChatBotLog.propTypes = {
+       id: PropTypes.number,
+};
+
+export default ChatBotLog;
diff --git a/resources/js/components/chat-bot-logs/Dialog.js b/resources/js/components/chat-bot-logs/Dialog.js
deleted file mode 100644 (file)
index ffe457c..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Button, Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import List from './List';
-import i18n from '../../i18n';
-
-class Dialog extends React.Component {
-
-       componentDidMount() {
-               this.timer = setInterval(() => {
-                       this.forceUpdate();
-               }, 30000);
-       }
-
-       componentWillUnmount() {
-               clearInterval(this.timer);
-       }
-
-       render() {
-               const {
-                       log,
-                       onHide,
-                       show,
-               } = this.props;
-               return <Modal className="chat-bot-log-dialog" onHide={onHide} show={show} size="lg">
-                       <Modal.Header closeButton>
-                               <Modal.Title>
-                                       {i18n.t('chatBotLog.heading')}
-                               </Modal.Title>
-                       </Modal.Header>
-                       {log && log.length ?
-                               <List log={log} />
-                       :
-                               <Modal.Body>
-                                       <Alert variant="info">
-                                               {i18n.t('chatBotLog.empty')}
-                                       </Alert>
-                               </Modal.Body>
-                       }
-                       <Modal.Footer>
-                               <Button onClick={onHide} variant="secondary">
-                                       {i18n.t('button.close')}
-                               </Button>
-                       </Modal.Footer>
-               </Modal>;
-       }
-
-}
-
-Dialog.propTypes = {
-       log: PropTypes.arrayOf(PropTypes.shape({
-       })),
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-};
-
-Dialog.defaultProps = {
-       log: null,
-       onHide: null,
-       show: false,
-};
-
-export default withTranslation()(Dialog);
diff --git a/resources/js/components/chat-bot-logs/Dialog.jsx b/resources/js/components/chat-bot-logs/Dialog.jsx
new file mode 100644 (file)
index 0000000..ffe457c
--- /dev/null
@@ -0,0 +1,65 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import List from './List';
+import i18n from '../../i18n';
+
+class Dialog extends React.Component {
+
+       componentDidMount() {
+               this.timer = setInterval(() => {
+                       this.forceUpdate();
+               }, 30000);
+       }
+
+       componentWillUnmount() {
+               clearInterval(this.timer);
+       }
+
+       render() {
+               const {
+                       log,
+                       onHide,
+                       show,
+               } = this.props;
+               return <Modal className="chat-bot-log-dialog" onHide={onHide} show={show} size="lg">
+                       <Modal.Header closeButton>
+                               <Modal.Title>
+                                       {i18n.t('chatBotLog.heading')}
+                               </Modal.Title>
+                       </Modal.Header>
+                       {log && log.length ?
+                               <List log={log} />
+                       :
+                               <Modal.Body>
+                                       <Alert variant="info">
+                                               {i18n.t('chatBotLog.empty')}
+                                       </Alert>
+                               </Modal.Body>
+                       }
+                       <Modal.Footer>
+                               <Button onClick={onHide} variant="secondary">
+                                       {i18n.t('button.close')}
+                               </Button>
+                       </Modal.Footer>
+               </Modal>;
+       }
+
+}
+
+Dialog.propTypes = {
+       log: PropTypes.arrayOf(PropTypes.shape({
+       })),
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+};
+
+Dialog.defaultProps = {
+       log: null,
+       onHide: null,
+       show: false,
+};
+
+export default withTranslation()(Dialog);
diff --git a/resources/js/components/chat-bot-logs/Item.js b/resources/js/components/chat-bot-logs/Item.js
deleted file mode 100644 (file)
index f50d078..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-import moment from 'moment';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { ListGroup } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import { getUserName } from '../../helpers/User';
-
-const getEntryDate = entry => moment(entry.created_at).fromNow();
-
-const getEntryOrigin = (entry, t) => {
-       return t('chatBotLog.origin.chatLog', {
-               channel: entry.origin.params[0],
-               date: new Date(entry.origin.created_at),
-               nick: entry.origin.nick,
-       });
-};
-
-const getEntryInfo = (entry, t) => {
-       if (entry.user && entry.category) {
-               return t('chatBotLog.info.userCat', {
-                       category: t(`twitchBot.chatCategories.${entry.category}`),
-                       date: getEntryDate(entry),
-                       user: getUserName(entry.user),
-               });
-       }
-       if (entry.category) {
-               return t('chatBotLog.info.cat', {
-                       category: t(`twitchBot.chatCategories.${entry.category}`),
-                       date: getEntryDate(entry),
-               });
-       }
-       if (entry.user) {
-               return t('chatBotLog.info.user', {
-                       date: getEntryDate(entry),
-                       user: getUserName(entry.user),
-               });
-       }
-       return getEntryDate(entry);
-};
-
-const Item = ({ entry }) => {
-       const { t } = useTranslation();
-
-       return <ListGroup.Item>
-               <div>
-                       <div>
-                               {entry.text}
-                       </div>
-                       {entry.origin ?
-                               <div
-                                       className="text-muted"
-                               >
-                                       {getEntryOrigin(entry, t)}
-                               </div>
-                       : null}
-                       <div
-                               className="text-muted"
-                               title={moment(entry.created_at).format('LLLL')}
-                       >
-                               {getEntryInfo(entry, t)}
-                       </div>
-               </div>
-       </ListGroup.Item>;
-};
-
-Item.propTypes = {
-       entry: PropTypes.shape({
-               created_at: PropTypes.string,
-               origin: PropTypes.shape({}),
-               text: PropTypes.string,
-       }),
-};
-
-Item.defaultProps = {
-       entry: {},
-};
-
-export default Item;
diff --git a/resources/js/components/chat-bot-logs/Item.jsx b/resources/js/components/chat-bot-logs/Item.jsx
new file mode 100644 (file)
index 0000000..395ad33
--- /dev/null
@@ -0,0 +1,143 @@
+import axios from 'axios';
+import moment from 'moment';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, ListGroup, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import ChannelLink from '../channel/Link';
+import List from '../chat-logs/List';
+import Icon from '../common/Icon';
+import Loading from '../common/Loading';
+import { getUserName } from '../../helpers/User';
+
+const getEntryDate = entry => moment(entry.created_at).fromNow();
+
+const getEntryOrigin = (entry, t) => {
+       return t('chatBotLog.origin.chatLog', {
+               channel: entry.origin.params[0],
+               date: new Date(entry.origin.created_at),
+               nick: entry.origin.nick,
+       });
+};
+
+const getEntryInfo = (entry, t) => {
+       if (entry.user && entry.category) {
+               return t('chatBotLog.info.userCat', {
+                       category: t(`twitchBot.chatCategories.${entry.category}`),
+                       date: getEntryDate(entry),
+                       user: getUserName(entry.user),
+               });
+       }
+       if (entry.category) {
+               return t('chatBotLog.info.cat', {
+                       category: t(`twitchBot.chatCategories.${entry.category}`),
+                       date: getEntryDate(entry),
+               });
+       }
+       if (entry.user) {
+               return t('chatBotLog.info.user', {
+                       date: getEntryDate(entry),
+                       user: getUserName(entry.user),
+               });
+       }
+       return getEntryDate(entry);
+};
+
+const Item = ({ entry = {} }) => {
+       const [context, setContext] = React.useState(null);
+       const [contextLoading, setContextLoading] = React.useState(true);
+       const [showContext, setShowContext] = React.useState(false);
+
+       const { t } = useTranslation();
+
+       React.useEffect(() => {
+               if (context || !showContext) return;
+               const ctrl = new AbortController();
+               axios
+                       .get(`/api/chatbotlogs/${entry.id}/context`, {
+                               signal: ctrl.signal
+                       })
+                       .then(response => {
+                               setContextLoading(false);
+                               setContext(response.data);
+                       })
+                       .catch(error => {
+                               if (!axios.isCancel(error)) {
+                                       setContextLoading(false);
+                                       setContext(null);
+                               }
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [context, showContext]);
+
+       return <ListGroup.Item>
+               <div className="d-flex justify-content-between">
+                       <div>
+                               <div>
+                                       {entry.text}
+                               </div>
+                               {entry.origin ?
+                                       <div
+                                               className="text-muted"
+                                       >
+                                               {getEntryOrigin(entry, t)}
+                                       </div>
+                               : null}
+                               <div
+                                       className="text-muted"
+                                       title={moment(entry.created_at).format('LLLL')}
+                               >
+                                       {getEntryInfo(entry, t)}
+                               </div>
+                       </div>
+                       <div>
+                               {entry.channel ?
+                                       <ChannelLink channel={entry.channel} />
+                               : null}
+                               <Button
+                                       className="ms-2"
+                                       onClick={() => { setShowContext(c => !c); }}
+                                       title={t('chatBotLog.showContext')}
+                                       variant={showContext ? 'secondary' : 'outline-secondary'}
+                               >
+                                       <Icon.PROTOCOL title="" />
+                               </Button>
+                       </div>
+               </div>
+               {showContext ?
+                       <div className="chat-bot-log-context mt-2">
+                               {contextLoading ?
+                                       <Loading />
+                               : null}
+                               {context ?
+                                       <Row>
+                                               <Col sm={6}>
+                                                       <h3 className="fs-6">{t('chatBotLog.context')}</h3>
+                                                       <List log={context.current} />
+                                               </Col>
+                                               {context.original ?
+                                                       <Col sm={6}>
+                                                               <h3 className="fs-6">{t('chatBotLog.originalContext')}</h3>
+                                                               <List log={context.original} />
+                                                       </Col>
+                                               : null}
+                                       </Row>
+                               : null}
+                       </div>
+               : null}
+       </ListGroup.Item>;
+};
+
+Item.propTypes = {
+       entry: PropTypes.shape({
+               channel: PropTypes.shape({}),
+               created_at: PropTypes.string,
+               origin: PropTypes.shape({}),
+               text: PropTypes.string,
+       }),
+};
+
+export default Item;
diff --git a/resources/js/components/chat-bot-logs/List.js b/resources/js/components/chat-bot-logs/List.js
deleted file mode 100644 (file)
index 9838b8e..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { ListGroup } from 'react-bootstrap';
-
-import Item from './Item';
-
-const List = ({ log }) =>
-       <ListGroup variant="flush">
-               {log ? log.map(entry =>
-                       <Item key={entry.id} entry={entry} />
-               ) : null}
-       </ListGroup>;
-
-List.propTypes = {
-       log: PropTypes.arrayOf(PropTypes.shape({
-       })),
-};
-
-List.defaultProps = {
-       log: [],
-};
-
-export default List;
diff --git a/resources/js/components/chat-bot-logs/List.jsx b/resources/js/components/chat-bot-logs/List.jsx
new file mode 100644 (file)
index 0000000..52a4de8
--- /dev/null
@@ -0,0 +1,40 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { ListGroup } from 'react-bootstrap';
+
+import Item from './Item';
+
+class List extends React.Component {
+
+       componentDidMount() {
+               this.timer = setInterval(() => {
+                       this.forceUpdate();
+               }, 30000);
+       }
+
+       componentWillUnmount() {
+               clearInterval(this.timer);
+       }
+
+       render() {
+               const { log } = this.props;
+
+               return <ListGroup variant="flush">
+                       {log ? log.map(entry =>
+                               <Item key={entry.id} entry={entry} />
+                       ) : null}
+               </ListGroup>;
+       }
+
+}
+
+List.propTypes = {
+       log: PropTypes.arrayOf(PropTypes.shape({
+       })),
+};
+
+List.defaultProps = {
+       log: [],
+};
+
+export default List;
diff --git a/resources/js/components/chat-logs/Item.jsx b/resources/js/components/chat-logs/Item.jsx
new file mode 100644 (file)
index 0000000..52110e3
--- /dev/null
@@ -0,0 +1,53 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+const getChatterColor = entry => {
+       if (entry.tags && entry.tags['color']) {
+               return entry.tags['color'];
+       }
+       return 'inherit';
+};
+
+const getChatterNick = entry => {
+       if (entry.tags && entry.tags['display-name']) {
+               return entry.tags['display-name'];
+       }
+       return entry.nick;
+};
+
+const getTextContent = entry => {
+       if (entry.params && entry.params.length >= 2) {
+               return entry.params[1];
+       }
+       return entry.text_content;
+};
+
+const getTimestamp = entry => {
+       if (entry.tags && entry.tags['tmi-sent-ts']) {
+               return new Date(parseInt(entry.tags['tmi-sent-ts'], 10));
+       }
+       return new Date(entry.created_at);
+};
+
+const Item = ({ entry }) => {
+       const { t } = useTranslation();
+
+       return <div className="chat-log-item">
+               <div>
+                       <span className="text-muted me-2">
+                               {t('chatBotLog.shortTimestamp', { date: getTimestamp(entry) })}
+                       </span>
+                       <strong style={{ color: getChatterColor(entry) }}>{getChatterNick(entry)}</strong>
+               </div>
+               <div>{getTextContent(entry)}</div>
+       </div>;
+};
+
+Item.propTypes = {
+       entry: PropTypes.shape({
+               text_content: PropTypes.string,
+       }).isRequired,
+};
+
+export default Item;
diff --git a/resources/js/components/chat-logs/List.jsx b/resources/js/components/chat-logs/List.jsx
new file mode 100644 (file)
index 0000000..8da17e2
--- /dev/null
@@ -0,0 +1,19 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Item from './Item';
+
+const List = ({ log = [] }) => {
+       return <div className="chat-log-list">
+               {log.map(entry =>
+                       <Item key={entry.id} entry={entry} />
+               )}
+       </div>;
+};
+
+List.propTypes = {
+       log: PropTypes.arrayOf(PropTypes.shape({
+       })),
+};
+
+export default List;
diff --git a/resources/js/components/common/AspectBox.js b/resources/js/components/common/AspectBox.js
deleted file mode 100644 (file)
index 52709c1..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-const AspectBox = ({ children, ratio }) =>
-       <div className="aspect-box-container" style={{ paddingTop: `${1 / ratio * 100}%`}}>
-               <div className="aspect-box-content">
-                       {children}
-               </div>
-       </div>;
-
-AspectBox.propTypes = {
-       children: PropTypes.node,
-       ratio: PropTypes.number,
-};
-
-AspectBox.defaultProps = {
-       children: null,
-       ratio: 1,
-};
-
-export default AspectBox;
diff --git a/resources/js/components/common/AspectBox.jsx b/resources/js/components/common/AspectBox.jsx
new file mode 100644 (file)
index 0000000..ead009d
--- /dev/null
@@ -0,0 +1,16 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+const AspectBox = ({ children = null, ratio = 1 }) =>
+       <div className="aspect-box-container" style={{ paddingTop: `${1 / ratio * 100}%`}}>
+               <div className="aspect-box-content">
+                       {children}
+               </div>
+       </div>;
+
+AspectBox.propTypes = {
+       children: PropTypes.node,
+       ratio: PropTypes.number,
+};
+
+export default AspectBox;
diff --git a/resources/js/components/common/CanonicalLinks.js b/resources/js/components/common/CanonicalLinks.js
deleted file mode 100644 (file)
index 26e8696..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-
-const CanonicalLinks = ({ base, lang, langs }) => {
-       const { i18n } = useTranslation();
-
-       const activeLang = lang || i18n.language;
-       const availableLangs = langs || ['de', 'en'];
-
-       return <Helmet>
-               <link
-                       href={`https://alttp.localhorst.tv${base}?lng=${activeLang}`}
-                       hrefLang={activeLang}
-                       rel="canonical"
-               />
-               <link
-                       href={`https://alttp.localhorst.tv${base}`}
-                       hrefLang="x-default"
-                       rel="alternate"
-               />
-               {availableLangs.filter(l => l !== activeLang).map(l =>
-                       <link
-                               key={l}
-                               href={`https://alttp.localhorst.tv${base}?lng=${l}`}
-                               hrefLang={l}
-                               rel="alternate"
-                       />
-               )}
-       </Helmet>;
-};
-
-CanonicalLinks.propTypes = {
-       base: PropTypes.string.isRequired,
-       lang: PropTypes.string,
-       langs: PropTypes.arrayOf(PropTypes.string),
-};
-
-export default CanonicalLinks;
diff --git a/resources/js/components/common/CanonicalLinks.jsx b/resources/js/components/common/CanonicalLinks.jsx
new file mode 100644 (file)
index 0000000..26e8696
--- /dev/null
@@ -0,0 +1,40 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+
+const CanonicalLinks = ({ base, lang, langs }) => {
+       const { i18n } = useTranslation();
+
+       const activeLang = lang || i18n.language;
+       const availableLangs = langs || ['de', 'en'];
+
+       return <Helmet>
+               <link
+                       href={`https://alttp.localhorst.tv${base}?lng=${activeLang}`}
+                       hrefLang={activeLang}
+                       rel="canonical"
+               />
+               <link
+                       href={`https://alttp.localhorst.tv${base}`}
+                       hrefLang="x-default"
+                       rel="alternate"
+               />
+               {availableLangs.filter(l => l !== activeLang).map(l =>
+                       <link
+                               key={l}
+                               href={`https://alttp.localhorst.tv${base}?lng=${l}`}
+                               hrefLang={l}
+                               rel="alternate"
+                       />
+               )}
+       </Helmet>;
+};
+
+CanonicalLinks.propTypes = {
+       base: PropTypes.string.isRequired,
+       lang: PropTypes.string,
+       langs: PropTypes.arrayOf(PropTypes.string),
+};
+
+export default CanonicalLinks;
diff --git a/resources/js/components/common/ChannelSelect.js b/resources/js/components/common/ChannelSelect.js
deleted file mode 100644 (file)
index a69662f..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React, { useCallback, useEffect, useRef, useState } from 'react';
-import { Alert, Button, Form, ListGroup } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from './Icon';
-import debounce from '../../helpers/debounce';
-
-const ChannelSelect = ({
-       autoSelect,
-       joinable,
-       manageable,
-       onChange,
-       readOnly,
-       value,
-}) => {
-       const [resolved, setResolved] = useState(null);
-       const [results, setResults] = useState([]);
-       const [search, setSearch] = useState('');
-       const [showResults, setShowResults] = useState(false);
-
-       const ref = useRef(null);
-       const { t } = useTranslation();
-
-       useEffect(() => {
-               const handleEventOutside = e => {
-                       if (ref.current && !ref.current.contains(e.target)) {
-                               setShowResults(false);
-                       }
-               };
-               document.addEventListener('click', handleEventOutside, true);
-               document.addEventListener('focus', handleEventOutside, true);
-               return () => {
-                       document.removeEventListener('click', handleEventOutside, true);
-                       document.removeEventListener('focus', handleEventOutside, true);
-               };
-       }, []);
-
-       let ctrl = null;
-       const fetch = useCallback(debounce(async phrase => {
-               if (ctrl) {
-                       ctrl.abort();
-               }
-               ctrl = new AbortController();
-               try {
-                       const response = await axios.get(`/api/channels`, {
-                               params: {
-                                       joinable: joinable ? 1 : 0,
-                                       manageable: manageable ? 1 : 0,
-                                       phrase,
-                               },
-                               signal: ctrl.signal,
-                       });
-                       ctrl = null;
-                       setResults(response.data);
-                       if (autoSelect && !phrase && response.data.length === 1) {
-                               onChange({
-                                       channel: response.data[0],
-                                       target: { value: response.data[0].id },
-                               });
-                       }
-               } catch (e) {
-                       ctrl = null;
-                       console.error(e);
-               }
-       }, 300), [autoSelect, joinable, manageable]);
-
-       useEffect(() => {
-               fetch(search);
-       }, [search]);
-
-       useEffect(() => {
-               if (value) {
-                       axios
-                               .get(`/api/channels/${value}`)
-                       .then(response => {
-                               setResolved(response.data);
-                       });
-               } else {
-                       setResolved(null);
-               }
-       }, [value]);
-
-       if (value) {
-               return <div className="d-flex align-items-center justify-content-between">
-                       <span>{resolved ? resolved.title : value}</span>
-                       {!readOnly ?
-                               <Button
-                                       className="ms-2"
-                                       onClick={() => onChange({ channel: null, target: { value: '' }})}
-                                       title={t('button.unset')}
-                                       variant="outline-danger"
-                               >
-                                       <Icon.REMOVE title="" />
-                               </Button>
-                       : null}
-               </div>;
-       }
-       return <div className={`channel-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
-               <Form.Control
-                       className="search-input"
-                       name={Math.random().toString(20).substr(2, 10)}
-                       onChange={e => setSearch(e.target.value)}
-                       onFocus={() => setShowResults(true)}
-                       readOnly={readOnly}
-                       type="search"
-                       value={search}
-               />
-               <div className="search-results-holder">
-                       {results.length ?
-                               <ListGroup className="search-results">
-                                       {results.map(result =>
-                                               <ListGroup.Item
-                                                       action
-                                                       key={result.id}
-                                                       onClick={() => onChange({
-                                                               channel: result,
-                                                               target: { value: result.id },
-                                                       })}
-                                               >
-                                                       {result.title}
-                                               </ListGroup.Item>
-                                       )}
-                               </ListGroup>
-                       :
-                               <Alert className="search-results" variant="info">
-                                       {t('search.noResults')}
-                               </Alert>
-                       }
-               </div>
-       </div>;
-};
-
-ChannelSelect.propTypes = {
-       autoSelect: PropTypes.bool,
-       joinable: PropTypes.bool,
-       manageable: PropTypes.bool,
-       onChange: PropTypes.func,
-       readOnly: PropTypes.bool,
-       value: PropTypes.oneOfType([
-               PropTypes.number,
-               PropTypes.string,
-       ]),
-};
-
-export default ChannelSelect;
diff --git a/resources/js/components/common/ChannelSelect.jsx b/resources/js/components/common/ChannelSelect.jsx
new file mode 100644 (file)
index 0000000..61b34e9
--- /dev/null
@@ -0,0 +1,148 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { Alert, Button, Form, ListGroup } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from './Icon';
+import debounce from '../../helpers/debounce';
+
+const ChannelSelect = ({
+       autoSelect,
+       joinable,
+       manageable,
+       onChange,
+       readOnly,
+       value,
+}) => {
+       const [resolved, setResolved] = useState(null);
+       const [results, setResults] = useState([]);
+       const [search, setSearch] = useState('');
+       const [showResults, setShowResults] = useState(false);
+
+       const ref = useRef(null);
+       const { t } = useTranslation();
+
+       useEffect(() => {
+               const handleEventOutside = e => {
+                       if (ref.current && !ref.current.contains(e.target)) {
+                               setShowResults(false);
+                       }
+               };
+               document.addEventListener('mousedown', handleEventOutside, true);
+               document.addEventListener('focus', handleEventOutside, true);
+               return () => {
+                       document.removeEventListener('mousedown', handleEventOutside, true);
+                       document.removeEventListener('focus', handleEventOutside, true);
+               };
+       }, []);
+
+       let ctrl = null;
+       const fetch = useCallback(debounce(async phrase => {
+               if (ctrl) {
+                       ctrl.abort();
+               }
+               ctrl = new AbortController();
+               try {
+                       const response = await axios.get(`/api/channels`, {
+                               params: {
+                                       joinable: joinable ? 1 : 0,
+                                       limit: 5,
+                                       manageable: manageable ? 1 : 0,
+                                       phrase,
+                               },
+                               signal: ctrl.signal,
+                       });
+                       ctrl = null;
+                       setResults(response.data);
+                       if (autoSelect && !phrase && response.data.length === 1) {
+                               onChange({
+                                       channel: response.data[0],
+                                       target: { value: response.data[0].id },
+                               });
+                       }
+               } catch (e) {
+                       ctrl = null;
+                       console.error(e);
+               }
+       }, 300), [autoSelect, joinable, manageable]);
+
+       useEffect(() => {
+               fetch(search);
+       }, [search]);
+
+       useEffect(() => {
+               if (value) {
+                       axios
+                               .get(`/api/channels/${value}`)
+                       .then(response => {
+                               setResolved(response.data);
+                       });
+               } else {
+                       setResolved(null);
+               }
+       }, [value]);
+
+       if (value) {
+               return <div className="d-flex align-items-center justify-content-between">
+                       <span>{resolved ? resolved.title : value}</span>
+                       {!readOnly ?
+                               <Button
+                                       className="ms-2"
+                                       onClick={() => onChange({ channel: null, target: { value: '' }})}
+                                       title={t('button.unset')}
+                                       variant="outline-danger"
+                               >
+                                       <Icon.REMOVE title="" />
+                               </Button>
+                       : null}
+               </div>;
+       }
+       return <div className={`channel-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
+               <Form.Control
+                       className="search-input"
+                       name={Math.random().toString(20).substr(2, 10)}
+                       onChange={e => setSearch(e.target.value)}
+                       onFocus={() => setShowResults(true)}
+                       readOnly={readOnly}
+                       type="search"
+                       value={search}
+               />
+               <div className="search-results-holder">
+                       {results.length ?
+                               <ListGroup className="search-results">
+                                       {results.map(result =>
+                                               <ListGroup.Item
+                                                       action
+                                                       key={result.id}
+                                                       onClick={() => onChange({
+                                                               channel: result,
+                                                               target: { value: result.id },
+                                                       })}
+                                               >
+                                                       {result.title}
+                                               </ListGroup.Item>
+                                       )}
+                               </ListGroup>
+                       :
+                               <Alert className="search-results" variant="info">
+                                       {t('search.noResults')}
+                               </Alert>
+                       }
+               </div>
+       </div>;
+};
+
+ChannelSelect.propTypes = {
+       autoSelect: PropTypes.bool,
+       joinable: PropTypes.bool,
+       manageable: PropTypes.bool,
+       onChange: PropTypes.func,
+       readOnly: PropTypes.bool,
+       value: PropTypes.oneOfType([
+               PropTypes.number,
+               PropTypes.string,
+       ]),
+};
+
+export default ChannelSelect;
diff --git a/resources/js/components/common/DiscordChannelSelect.js b/resources/js/components/common/DiscordChannelSelect.js
deleted file mode 100644 (file)
index fd5fe8d..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React, { useCallback, useEffect, useState } from 'react';
-import { Alert, Button, Form, ListGroup } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from './Icon';
-import ChannelBox from '../discord-guilds/ChannelBox';
-import debounce from '../../helpers/debounce';
-
-const DiscordChannelSelect = ({
-       guild,
-       isInvalid,
-       name,
-       onBlur,
-       onChange,
-       types,
-       value,
-}) => {
-       const [resolved, setResolved] = useState(null);
-       const [results, setResults] = useState([]);
-       const [search, setSearch] = useState('');
-       const [showResults, setShowResults] = useState(false);
-
-       const ref = React.useRef(null);
-       const { t } = useTranslation();
-
-       useEffect(() => {
-               const handleEventOutside = e => {
-                       if (ref.current && !ref.current.contains(e.target)) {
-                               setShowResults(false);
-                       }
-               };
-               document.addEventListener('click', handleEventOutside, true);
-               document.addEventListener('focus', handleEventOutside, true);
-               return () => {
-                       document.removeEventListener('click', handleEventOutside, true);
-                       document.removeEventListener('focus', handleEventOutside, true);
-               };
-       }, []);
-
-       let ctrl = null;
-       const fetch = useCallback(debounce(async (guild, phrase, types) => {
-               if (ctrl) {
-                       ctrl.abort();
-               }
-               ctrl = new AbortController();
-               try {
-                       const response = await axios.get(`/api/discord-guilds/${guild}/channels`, {
-                               params: {
-                                       phrase,
-                                       types,
-                               },
-                               signal: ctrl.signal,
-                       });
-                       ctrl = null;
-                       setResults(response.data);
-               } catch (e) {
-                       ctrl = null;
-                       console.error(e);
-               }
-               return () => {
-                       if (ctrl) ctrl.abort();
-               };
-       }, 300), []);
-
-       useEffect(() => {
-               fetch(guild, search, types);
-       }, [guild, search, ...types]);
-
-       useEffect(() => {
-               if (value) {
-                       axios
-                               .get(`/api/discord-channels/${value}`)
-                       .then(response => {
-                               setResolved(response.data);
-                       });
-               } else {
-                       setResolved(null);
-               }
-       }, [value]);
-
-       if (value) {
-               return <div className="d-flex align-items-center justify-content-between">
-                       <span>{resolved ? <ChannelBox channel={resolved} /> : value}</span>
-                       <Button
-                               className="ms-2"
-                               onClick={() => onChange({ guild: null, target: { name, value: '' }})}
-                               title={t('button.unset')}
-                               variant="outline-danger"
-                       >
-                               <Icon.REMOVE title="" />
-                       </Button>
-               </div>;
-       }
-       return <div className={`discord-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
-               <Form.Control
-                       className="search-input"
-                       name={Math.random().toString(20).substr(2, 10)}
-                       onChange={e => setSearch(e.target.value)}
-                       onFocus={() => setShowResults(true)}
-                       type="search"
-                       value={search}
-               />
-               <div className="search-results-holder">
-                       {results.length ?
-                               <ListGroup className="search-results">
-                                       {results.map(result =>
-                                               <ListGroup.Item
-                                                       action
-                                                       key={result.id}
-                                                       onClick={() => onChange({
-                                                               channel: result,
-                                                               target: { name, value: result.channel_id },
-                                                       })}
-                                               >
-                                                       <ChannelBox channel={result} />
-                                               </ListGroup.Item>
-                                       )}
-                               </ListGroup>
-                       :
-                               <Alert className="search-results" variant="info">
-                                       {t('search.noResults')}
-                               </Alert>
-                       }
-               </div>
-       </div>;
-};
-
-DiscordChannelSelect.propTypes = {
-       guild: PropTypes.string,
-       isInvalid: PropTypes.bool,
-       name: PropTypes.string,
-       onBlur: PropTypes.func,
-       onChange: PropTypes.func,
-       types: PropTypes.arrayOf(PropTypes.number),
-       value: PropTypes.string,
-};
-
-export default DiscordChannelSelect;
diff --git a/resources/js/components/common/DiscordChannelSelect.jsx b/resources/js/components/common/DiscordChannelSelect.jsx
new file mode 100644 (file)
index 0000000..653db1a
--- /dev/null
@@ -0,0 +1,138 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React, { useCallback, useEffect, useState } from 'react';
+import { Alert, Button, Form, ListGroup } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from './Icon';
+import ChannelBox from '../discord-guilds/ChannelBox';
+import debounce from '../../helpers/debounce';
+
+const DiscordChannelSelect = ({
+       guild,
+       name,
+       onChange,
+       types,
+       value,
+}) => {
+       const [resolved, setResolved] = useState(null);
+       const [results, setResults] = useState([]);
+       const [search, setSearch] = useState('');
+       const [showResults, setShowResults] = useState(false);
+
+       const ref = React.useRef(null);
+       const { t } = useTranslation();
+
+       useEffect(() => {
+               const handleEventOutside = e => {
+                       if (ref.current && !ref.current.contains(e.target)) {
+                               setShowResults(false);
+                       }
+               };
+               document.addEventListener('mousedown', handleEventOutside, true);
+               document.addEventListener('focus', handleEventOutside, true);
+               return () => {
+                       document.removeEventListener('mousedown', handleEventOutside, true);
+                       document.removeEventListener('focus', handleEventOutside, true);
+               };
+       }, []);
+
+       let ctrl = null;
+       const fetch = useCallback(debounce(async (guild, phrase, types) => {
+               if (ctrl) {
+                       ctrl.abort();
+               }
+               ctrl = new AbortController();
+               try {
+                       const response = await axios.get(`/api/discord-guilds/${guild}/channels`, {
+                               params: {
+                                       phrase,
+                                       types,
+                               },
+                               signal: ctrl.signal,
+                       });
+                       ctrl = null;
+                       setResults(response.data);
+               } catch (e) {
+                       ctrl = null;
+                       console.error(e);
+               }
+               return () => {
+                       if (ctrl) ctrl.abort();
+               };
+       }, 300), []);
+
+       useEffect(() => {
+               fetch(guild, search, types);
+       }, [guild, search, ...types]);
+
+       useEffect(() => {
+               if (value) {
+                       axios
+                               .get(`/api/discord-channels/${value}`)
+                       .then(response => {
+                               setResolved(response.data);
+                       });
+               } else {
+                       setResolved(null);
+               }
+       }, [value]);
+
+       if (value) {
+               return <div className="d-flex align-items-center justify-content-between">
+                       <span>{resolved ? <ChannelBox channel={resolved} /> : value}</span>
+                       <Button
+                               className="ms-2"
+                               onClick={() => onChange({ channel: null, target: { name, value: '' }})}
+                               title={t('button.unset')}
+                               variant="outline-danger"
+                       >
+                               <Icon.REMOVE title="" />
+                       </Button>
+               </div>;
+       }
+       return <div className={`discord-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
+               <Form.Control
+                       className="search-input"
+                       name={Math.random().toString(20).substr(2, 10)}
+                       onChange={e => setSearch(e.target.value)}
+                       onFocus={() => setShowResults(true)}
+                       type="search"
+                       value={search}
+               />
+               <div className="search-results-holder">
+                       {results.length ?
+                               <ListGroup className="search-results">
+                                       {results.map(result =>
+                                               <ListGroup.Item
+                                                       action
+                                                       key={result.id}
+                                                       onClick={() => onChange({
+                                                               channel: result,
+                                                               target: { name, value: result.channel_id },
+                                                       })}
+                                               >
+                                                       <ChannelBox channel={result} />
+                                               </ListGroup.Item>
+                                       )}
+                               </ListGroup>
+                       :
+                               <Alert className="search-results" variant="info">
+                                       {t('search.noResults')}
+                               </Alert>
+                       }
+               </div>
+       </div>;
+};
+
+DiscordChannelSelect.propTypes = {
+       guild: PropTypes.string,
+       isInvalid: PropTypes.bool,
+       name: PropTypes.string,
+       onBlur: PropTypes.func,
+       onChange: PropTypes.func,
+       types: PropTypes.arrayOf(PropTypes.number),
+       value: PropTypes.string,
+};
+
+export default DiscordChannelSelect;
diff --git a/resources/js/components/common/DiscordSelect.js b/resources/js/components/common/DiscordSelect.js
deleted file mode 100644 (file)
index 65c94d6..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React, { useCallback, useEffect, useRef, useState } from 'react';
-import { Alert, Button, Form, ListGroup } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from './Icon';
-import GuildBox from '../discord-guilds/Box';
-import debounce from '../../helpers/debounce';
-
-const DiscordSelect = ({ onChange, value }) => {
-       const [resolved, setResolved] = useState(null);
-       const [results, setResults] = useState([]);
-       const [search, setSearch] = useState('');
-       const [showResults, setShowResults] = useState(false);
-
-       const ref = useRef(null);
-       const { t } = useTranslation();
-
-       useEffect(() => {
-               const handleEventOutside = e => {
-                       if (ref.current && !ref.current.contains(e.target)) {
-                               setShowResults(false);
-                       }
-               };
-               document.addEventListener('click', handleEventOutside, true);
-               document.addEventListener('focus', handleEventOutside, true);
-               return () => {
-                       document.removeEventListener('click', handleEventOutside, true);
-                       document.removeEventListener('focus', handleEventOutside, true);
-               };
-       }, []);
-
-       let ctrl = null;
-       const fetch = useCallback(debounce(async phrase => {
-               if (ctrl) {
-                       ctrl.abort();
-               }
-               ctrl = new AbortController();
-               try {
-                       const response = await axios.get(`/api/discord-guilds`, {
-                               params: {
-                                       phrase,
-                               },
-                               signal: ctrl.signal,
-                       });
-                       ctrl = null;
-                       setResults(response.data);
-               } catch (e) {
-                       ctrl = null;
-                       console.error(e);
-               }
-       }, 300), []);
-
-       useEffect(() => {
-               fetch(search);
-       }, [search]);
-
-       useEffect(() => {
-               if (value) {
-                       axios
-                               .get(`/api/discord-guilds/${value}`)
-                       .then(response => {
-                               setResolved(response.data);
-                       });
-               } else {
-                       setResolved(null);
-               }
-       }, [value]);
-
-       if (value) {
-               return <div className="d-flex align-items-center justify-content-between">
-                       <span>{resolved ? <GuildBox guild={resolved} /> : value}</span>
-                       <Button
-                               className="ms-2"
-                               onClick={() => onChange({ guild: null, target: { value: '' }})}
-                               title={t('button.unset')}
-                               variant="outline-danger"
-                       >
-                               <Icon.REMOVE title="" />
-                       </Button>
-               </div>;
-       }
-       return <div className={`discord-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
-               <Form.Control
-                       className="search-input"
-                       name={Math.random().toString(20).substr(2, 10)}
-                       onChange={e => setSearch(e.target.value)}
-                       onFocus={() => setShowResults(true)}
-                       type="search"
-                       value={search}
-               />
-               <div className="search-results-holder">
-                       {results.length ?
-                               <ListGroup className="search-results">
-                                       {results.map(result =>
-                                               <ListGroup.Item
-                                                       action
-                                                       key={result.id}
-                                                       onClick={() => onChange({
-                                                               guild: result,
-                                                               target: { value: result.guild_id },
-                                                       })}
-                                               >
-                                                       <GuildBox guild={result} />
-                                               </ListGroup.Item>
-                                       )}
-                               </ListGroup>
-                       :
-                               <Alert className="search-results" variant="info">
-                                       {t('search.noResults')}
-                               </Alert>
-                       }
-               </div>
-       </div>;
-};
-
-DiscordSelect.propTypes = {
-       onChange: PropTypes.func,
-       value: PropTypes.string,
-};
-
-export default DiscordSelect;
diff --git a/resources/js/components/common/DiscordSelect.jsx b/resources/js/components/common/DiscordSelect.jsx
new file mode 100644 (file)
index 0000000..9ac7b56
--- /dev/null
@@ -0,0 +1,123 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { Alert, Button, Form, ListGroup } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from './Icon';
+import GuildBox from '../discord-guilds/Box';
+import debounce from '../../helpers/debounce';
+
+const DiscordSelect = ({ onChange, value }) => {
+       const [resolved, setResolved] = useState(null);
+       const [results, setResults] = useState([]);
+       const [search, setSearch] = useState('');
+       const [showResults, setShowResults] = useState(false);
+
+       const ref = useRef(null);
+       const { t } = useTranslation();
+
+       useEffect(() => {
+               const handleEventOutside = e => {
+                       if (ref.current && !ref.current.contains(e.target)) {
+                               setShowResults(false);
+                       }
+               };
+               document.addEventListener('mousedown', handleEventOutside, true);
+               document.addEventListener('focus', handleEventOutside, true);
+               return () => {
+                       document.removeEventListener('mousedown', handleEventOutside, true);
+                       document.removeEventListener('focus', handleEventOutside, true);
+               };
+       }, []);
+
+       let ctrl = null;
+       const fetch = useCallback(debounce(async phrase => {
+               if (ctrl) {
+                       ctrl.abort();
+               }
+               ctrl = new AbortController();
+               try {
+                       const response = await axios.get(`/api/discord-guilds`, {
+                               params: {
+                                       phrase,
+                               },
+                               signal: ctrl.signal,
+                       });
+                       ctrl = null;
+                       setResults(response.data);
+               } catch (e) {
+                       ctrl = null;
+                       console.error(e);
+               }
+       }, 300), []);
+
+       useEffect(() => {
+               fetch(search);
+       }, [search]);
+
+       useEffect(() => {
+               if (value) {
+                       axios
+                               .get(`/api/discord-guilds/${value}`)
+                       .then(response => {
+                               setResolved(response.data);
+                       });
+               } else {
+                       setResolved(null);
+               }
+       }, [value]);
+
+       if (value) {
+               return <div className="d-flex align-items-center justify-content-between">
+                       <span>{resolved ? <GuildBox guild={resolved} /> : value}</span>
+                       <Button
+                               className="ms-2"
+                               onClick={() => onChange({ guild: null, target: { value: '' }})}
+                               title={t('button.unset')}
+                               variant="outline-danger"
+                       >
+                               <Icon.REMOVE title="" />
+                       </Button>
+               </div>;
+       }
+       return <div className={`discord-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
+               <Form.Control
+                       className="search-input"
+                       name={Math.random().toString(20).substr(2, 10)}
+                       onChange={e => setSearch(e.target.value)}
+                       onFocus={() => setShowResults(true)}
+                       type="search"
+                       value={search}
+               />
+               <div className="search-results-holder">
+                       {results.length ?
+                               <ListGroup className="search-results">
+                                       {results.map(result =>
+                                               <ListGroup.Item
+                                                       action
+                                                       key={result.id}
+                                                       onClick={() => onChange({
+                                                               guild: result,
+                                                               target: { value: result.guild_id },
+                                                       })}
+                                               >
+                                                       <GuildBox guild={result} />
+                                               </ListGroup.Item>
+                                       )}
+                               </ListGroup>
+                       :
+                               <Alert className="search-results" variant="info">
+                                       {t('search.noResults')}
+                               </Alert>
+                       }
+               </div>
+       </div>;
+};
+
+DiscordSelect.propTypes = {
+       onChange: PropTypes.func,
+       value: PropTypes.string,
+};
+
+export default DiscordSelect;
diff --git a/resources/js/components/common/ErrorBoundary.js b/resources/js/components/common/ErrorBoundary.js
deleted file mode 100644 (file)
index 83fdb3e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import ErrorMessage from './ErrorMessage';
-
-class ErrorBoundary extends React.Component {
-       constructor(props) {
-               super(props);
-               this.state = {
-                       error: null,
-               };
-       }
-
-       static getDerivedStateFromError(error) {
-               return { error };
-       }
-
-       componentDidCatch(error, errorInfo) {
-               console.log(error, errorInfo);
-       }
-
-       render() {
-               const { children } = this.props;
-               const { error } = this.state;
-               if (error) {
-                       return <ErrorMessage error={error} />;
-               }
-               return children;
-       }
-}
-
-ErrorBoundary.propTypes = {
-       children: PropTypes.node,
-};
-
-export default ErrorBoundary;
diff --git a/resources/js/components/common/ErrorBoundary.jsx b/resources/js/components/common/ErrorBoundary.jsx
new file mode 100644 (file)
index 0000000..83fdb3e
--- /dev/null
@@ -0,0 +1,36 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import ErrorMessage from './ErrorMessage';
+
+class ErrorBoundary extends React.Component {
+       constructor(props) {
+               super(props);
+               this.state = {
+                       error: null,
+               };
+       }
+
+       static getDerivedStateFromError(error) {
+               return { error };
+       }
+
+       componentDidCatch(error, errorInfo) {
+               console.log(error, errorInfo);
+       }
+
+       render() {
+               const { children } = this.props;
+               const { error } = this.state;
+               if (error) {
+                       return <ErrorMessage error={error} />;
+               }
+               return children;
+       }
+}
+
+ErrorBoundary.propTypes = {
+       children: PropTypes.node,
+};
+
+export default ErrorBoundary;
diff --git a/resources/js/components/common/ErrorMessage.js b/resources/js/components/common/ErrorMessage.js
deleted file mode 100644 (file)
index 2430bc2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import i18n from '../../i18n';
-
-const ErrorMessage = ({ error }) => {
-       if (error.response) {
-               return <Alert variant="danger">
-                       <Alert.Heading>{i18n.t(`error.${error.response.status}.heading`)}</Alert.Heading>
-                       <p className="mb-0">{i18n.t(`error.${error.response.status}.description`)}</p>
-               </Alert>;
-       }
-       if (error.message) {
-               return <Alert variant="danger">
-                       <Alert.Heading>Error</Alert.Heading>
-                       <p className="mb-0">{error.message}</p>
-               </Alert>;
-       }
-       return <div className="error">Error</div>;
-};
-
-ErrorMessage.propTypes = {
-       error: PropTypes.shape({
-               message: PropTypes.string,
-               request: PropTypes.shape({}),
-               response: PropTypes.shape({
-                       status: PropTypes.number,
-               }),
-       }),
-};
-
-export default withTranslation()(ErrorMessage);
diff --git a/resources/js/components/common/ErrorMessage.jsx b/resources/js/components/common/ErrorMessage.jsx
new file mode 100644 (file)
index 0000000..2430bc2
--- /dev/null
@@ -0,0 +1,34 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import i18n from '../../i18n';
+
+const ErrorMessage = ({ error }) => {
+       if (error.response) {
+               return <Alert variant="danger">
+                       <Alert.Heading>{i18n.t(`error.${error.response.status}.heading`)}</Alert.Heading>
+                       <p className="mb-0">{i18n.t(`error.${error.response.status}.description`)}</p>
+               </Alert>;
+       }
+       if (error.message) {
+               return <Alert variant="danger">
+                       <Alert.Heading>Error</Alert.Heading>
+                       <p className="mb-0">{error.message}</p>
+               </Alert>;
+       }
+       return <div className="error">Error</div>;
+};
+
+ErrorMessage.propTypes = {
+       error: PropTypes.shape({
+               message: PropTypes.string,
+               request: PropTypes.shape({}),
+               response: PropTypes.shape({
+                       status: PropTypes.number,
+               }),
+       }),
+};
+
+export default withTranslation()(ErrorMessage);
diff --git a/resources/js/components/common/HTMLInput.js b/resources/js/components/common/HTMLInput.js
deleted file mode 100644 (file)
index 8a54842..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-import { html } from '@codemirror/lang-html';
-import { EditorView } from '@codemirror/view';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { githubDark } from '@uiw/codemirror-theme-github';
-import CodeMirror from '@uiw/react-codemirror';
-
-const HTMLInput = ({
-       name,
-       onChange,
-       value,
-}) => {
-       const handleChange = React.useCallback((value) => {
-               return onChange({ target: { name, value } });
-       }, [name, onChange]);
-
-       return <CodeMirror
-               extensions={[html(), EditorView.lineWrapping]}
-               onChange={handleChange}
-               theme={githubDark}
-               value={value}
-       />;
-};
-
-HTMLInput.propTypes = {
-       name: PropTypes.string,
-       onChange: PropTypes.func,
-       value: PropTypes.string,
-};
-
-export default HTMLInput;
diff --git a/resources/js/components/common/HTMLInput.jsx b/resources/js/components/common/HTMLInput.jsx
new file mode 100644 (file)
index 0000000..8a54842
--- /dev/null
@@ -0,0 +1,31 @@
+import { html } from '@codemirror/lang-html';
+import { EditorView } from '@codemirror/view';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { githubDark } from '@uiw/codemirror-theme-github';
+import CodeMirror from '@uiw/react-codemirror';
+
+const HTMLInput = ({
+       name,
+       onChange,
+       value,
+}) => {
+       const handleChange = React.useCallback((value) => {
+               return onChange({ target: { name, value } });
+       }, [name, onChange]);
+
+       return <CodeMirror
+               extensions={[html(), EditorView.lineWrapping]}
+               onChange={handleChange}
+               theme={githubDark}
+               value={value}
+       />;
+};
+
+HTMLInput.propTypes = {
+       name: PropTypes.string,
+       onChange: PropTypes.func,
+       value: PropTypes.string,
+};
+
+export default HTMLInput;
diff --git a/resources/js/components/common/Icon.js b/resources/js/components/common/Icon.js
deleted file mode 100644 (file)
index f3caeb3..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { fab } from '@fortawesome/free-brands-svg-icons';
-import { fas } from '@fortawesome/free-solid-svg-icons';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { withTranslation } from 'react-i18next';
-
-import i18n from '../../i18n';
-
-library.add(fab);
-library.add(fas);
-
-const Icon = ({
-       alt,
-       className,
-       name,
-       size,
-       title,
-}) =>
-       <FontAwesomeIcon
-               icon={name}
-               alt={alt}
-               className={name === Icon.LOADING ? `${className} fa-spin` : className}
-               size={size}
-               title={title}
-       />
-;
-
-Icon.propTypes = {
-       name: PropTypes.oneOfType([
-               PropTypes.string,
-               PropTypes.arrayOf(PropTypes.string),
-       ]).isRequired,
-       alt: PropTypes.string,
-       className: PropTypes.string,
-       size: PropTypes.string,
-       title: PropTypes.string,
-};
-
-Icon.defaultProps = {
-       alt: null,
-       className: '',
-       size: null,
-       title: null,
-};
-
-const makePreset = (presetDisplayName, presetName) => {
-       const preset = ({ alt, className, name, size, title}) => <Icon
-               alt={alt || i18n.t(`icon.${presetDisplayName}`)}
-               className={className}
-               name={name || presetName}
-               size={size}
-               title={title !== '' ? title || alt || i18n.t(`icon.${presetDisplayName}`) : null}
-       />;
-       preset.displayName = presetDisplayName;
-       return withTranslation()(preset);
-};
-
-Icon.ACCEPT = makePreset('AcceptIcon', 'square-check');
-Icon.ADD = makePreset('AddIcon', 'circle-plus');
-Icon.ALLOWED = makePreset('AllowedIcon', 'square-check');
-Icon.APPLY = makePreset('ApplyIcon', 'right-to-bracket');
-Icon.APPLICATIONS = makePreset('ApplicationsIcon', 'person-running');
-Icon.BROWSER_SOURCE = makePreset('BrowserSourceIcon', 'tv');
-Icon.CHART = makePreset('ChartIcon', 'chart-line');
-Icon.CROSSHAIRS = makePreset('CrosshairsIcon', 'crosshairs');
-Icon.DELETE = makePreset('DeleteIcon', 'user-xmark');
-Icon.DISCORD = makePreset('DiscordIcon', ['fab', 'discord']);
-Icon.EDIT = makePreset('EditIcon', 'edit');
-Icon.FILTER = makePreset('FilterIcon', 'filter');
-Icon.FINISHED = makePreset('FinishedIcon', 'square-check');
-Icon.FIRST_PLACE = makePreset('FirstPlaceIcon', 'trophy');
-Icon.FORBIDDEN = makePreset('ForbiddenIcon', 'square-xmark');
-Icon.FORFEIT = makePreset('ForfeitIcon', 'square-xmark');
-Icon.HASH = makePreset('HashIcon', 'hashtag');
-Icon.INFO = makePreset('Info', 'circle-info');
-Icon.INVERT = makePreset('InvertIcon', 'circle-half-stroke');
-Icon.LANGUAGE = makePreset('LanguageIcon', 'language');
-Icon.LOCKED = makePreset('LockedIcon', 'lock');
-Icon.LOGOUT = makePreset('LogoutIcon', 'sign-out-alt');
-Icon.MENU = makePreset('MenuIcon', 'bars');
-Icon.MICROPHONE = makePreset('MicrophoneIcon', 'microphone');
-Icon.MONITOR = makePreset('MonitorIcon', 'tv');
-Icon.MOUSE = makePreset('MouseIcon', 'arrow-pointer');
-Icon.OPEN = makePreset('OpenIcon', 'arrow-up-right-from-square');
-Icon.PAUSE = makePreset('PauseIcon', 'pause');
-Icon.PENDING = makePreset('PendingIcon', 'clock');
-Icon.PIN = makePreset('PinIcon', 'location-pin');
-Icon.PLAY = makePreset('PlayIcon', 'play');
-Icon.PROTOCOL = makePreset('ProtocolIcon', 'file-alt');
-Icon.RACETIME = makePreset('RacetimeIcon', 'stopwatch');
-Icon.REJECT = makePreset('RejectIcon', 'square-xmark');
-Icon.REMOVE = makePreset('RemoveIcon', 'square-xmark');
-Icon.RESULT = makePreset('ResultIcon', 'clock');
-Icon.SECOND_PLACE = makePreset('SecondPlaceIcon', 'medal');
-Icon.SETTINGS = makePreset('SettingsIcon', 'cog');
-Icon.SLASH = makePreset('SlashIcon', 'slash');
-Icon.STEP_BACKWARD = makePreset('StepBackwardIcon', 'backward-step');
-Icon.STEP_FORWARD = makePreset('StepForwardIcon', 'forward-step');
-Icon.STOP = makePreset('StopIcon', 'stop');
-Icon.STREAM = makePreset('StreamIcon', ['fab', 'twitch']);
-Icon.THIRD_PLACE = makePreset('ThirdPlaceIcon', 'award');
-Icon.TWITCH = makePreset('TwitchIcon', ['fab', 'twitch']);
-Icon.UNKNOWN = makePreset('UnknownIcon', 'square-question');
-Icon.UNLOCKED = makePreset('UnlockedIcon', 'lock-open');
-Icon.VIDEO = makePreset('VideoIcon', 'video');
-Icon.WARNING = makePreset('WarningIcon', 'triangle-exclamation');
-Icon.VOLUME = makePreset('VolumeIcon', 'volume-high');
-Icon.YOUTUBE = makePreset('YoutubeIcon', ['fab', 'youtube']);
-
-export default Icon;
diff --git a/resources/js/components/common/Icon.jsx b/resources/js/components/common/Icon.jsx
new file mode 100644 (file)
index 0000000..ff676c1
--- /dev/null
@@ -0,0 +1,109 @@
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { fab } from '@fortawesome/free-brands-svg-icons';
+import { fas } from '@fortawesome/free-solid-svg-icons';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+import i18n from '../../i18n';
+
+library.add(fab);
+library.add(fas);
+
+const Icon = ({
+       alt = null,
+       className = '',
+       name,
+       size = null,
+       title = null,
+}) =>
+       <FontAwesomeIcon
+               icon={name}
+               alt={alt}
+               className={name === Icon.LOADING ? `${className} fa-spin` : className}
+               size={size}
+               title={title}
+       />
+;
+
+Icon.propTypes = {
+       name: PropTypes.oneOfType([
+               PropTypes.string,
+               PropTypes.arrayOf(PropTypes.string),
+       ]).isRequired,
+       alt: PropTypes.string,
+       className: PropTypes.string,
+       size: PropTypes.string,
+       title: PropTypes.string,
+};
+
+const makePreset = (presetDisplayName, presetName) => {
+       const preset = ({ alt, className, name, size, title}) => <Icon
+               alt={alt || i18n.t(`icon.${presetDisplayName}`)}
+               className={className}
+               name={name || presetName}
+               size={size}
+               title={title !== '' ? title || alt || i18n.t(`icon.${presetDisplayName}`) : null}
+       />;
+       preset.displayName = presetDisplayName;
+       return withTranslation()(preset);
+};
+
+Icon.ACCEPT = makePreset('AcceptIcon', 'square-check');
+Icon.ADD = makePreset('AddIcon', 'circle-plus');
+Icon.ALLOWED = makePreset('AllowedIcon', 'square-check');
+Icon.APPLY = makePreset('ApplyIcon', 'right-to-bracket');
+Icon.APPLICATIONS = makePreset('ApplicationsIcon', 'person-running');
+Icon.BROWSER_SOURCE = makePreset('BrowserSourceIcon', 'tv');
+Icon.CHART = makePreset('ChartIcon', 'chart-line');
+Icon.CROSSHAIRS = makePreset('CrosshairsIcon', 'crosshairs');
+Icon.DELETE = makePreset('DeleteIcon', 'user-xmark');
+Icon.DISCORD = makePreset('DiscordIcon', ['fab', 'discord']);
+Icon.EDIT = makePreset('EditIcon', 'edit');
+Icon.FILTER = makePreset('FilterIcon', 'filter');
+Icon.FINISHED = makePreset('FinishedIcon', 'square-check');
+Icon.FIRST_PLACE = makePreset('FirstPlaceIcon', 'trophy');
+Icon.FORBIDDEN = makePreset('ForbiddenIcon', 'square-xmark');
+Icon.FORFEIT = makePreset('ForfeitIcon', 'square-xmark');
+Icon.HASH = makePreset('HashIcon', 'hashtag');
+Icon.INFO = makePreset('Info', 'circle-info');
+Icon.INVERT = makePreset('InvertIcon', 'circle-half-stroke');
+Icon.LANGUAGE = makePreset('LanguageIcon', 'language');
+Icon.LOAD = makePreset('LoadIcon', 'upload');
+Icon.LOCKED = makePreset('LockedIcon', 'lock');
+Icon.LOGOUT = makePreset('LogoutIcon', 'sign-out-alt');
+Icon.MENU = makePreset('MenuIcon', 'bars');
+Icon.MICROPHONE = makePreset('MicrophoneIcon', 'microphone');
+Icon.MONITOR = makePreset('MonitorIcon', 'tv');
+Icon.MOUSE = makePreset('MouseIcon', 'arrow-pointer');
+Icon.OPEN = makePreset('OpenIcon', 'arrow-up-right-from-square');
+Icon.PAUSE = makePreset('PauseIcon', 'pause');
+Icon.PENDING = makePreset('PendingIcon', 'clock');
+Icon.PIN = makePreset('PinIcon', 'location-pin');
+Icon.PLAY = makePreset('PlayIcon', 'play');
+Icon.PROTOCOL = makePreset('ProtocolIcon', 'file-alt');
+Icon.RACETIME = makePreset('RacetimeIcon', 'stopwatch');
+Icon.REJECT = makePreset('RejectIcon', 'square-xmark');
+Icon.REMOVE = makePreset('RemoveIcon', 'square-xmark');
+Icon.RESET = makePreset('ResetIcon', 'rotate-left');
+Icon.RESULT = makePreset('ResultIcon', 'clock');
+Icon.SAVE = makePreset('SaveIcon', 'download');
+Icon.SECOND_PLACE = makePreset('SecondPlaceIcon', 'medal');
+Icon.SETTINGS = makePreset('SettingsIcon', 'cog');
+Icon.SLASH = makePreset('SlashIcon', 'slash');
+Icon.STEP_BACKWARD = makePreset('StepBackwardIcon', 'backward-step');
+Icon.STEP_FORWARD = makePreset('StepForwardIcon', 'forward-step');
+Icon.STOP = makePreset('StopIcon', 'stop');
+Icon.STREAM = makePreset('StreamIcon', ['fab', 'twitch']);
+Icon.THIRD_PLACE = makePreset('ThirdPlaceIcon', 'award');
+Icon.TIME_REVERSE = makePreset('TimeReverseIcon', 'clock-rotate-left');
+Icon.TWITCH = makePreset('TwitchIcon', ['fab', 'twitch']);
+Icon.UNKNOWN = makePreset('UnknownIcon', 'square-question');
+Icon.UNLOCKED = makePreset('UnlockedIcon', 'lock-open');
+Icon.VIDEO = makePreset('VideoIcon', 'video');
+Icon.WARNING = makePreset('WarningIcon', 'triangle-exclamation');
+Icon.VOLUME = makePreset('VolumeIcon', 'volume-high');
+Icon.YOUTUBE = makePreset('YoutubeIcon', ['fab', 'youtube']);
+
+export default Icon;
diff --git a/resources/js/components/common/LargeCheck.js b/resources/js/components/common/LargeCheck.js
deleted file mode 100644 (file)
index e159b45..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Icon from './Icon';
-
-const LargeCheck = ({
-       className,
-       id,
-       name,
-       onBlur,
-       onChange,
-       value,
-}) => {
-       let clsn = className ? `${className} custom-check` : 'custom-check';
-       if (value) {
-               clsn += ' checked';
-       }
-       return <span
-               className={clsn}
-               id={id}
-               onBlur={onBlur ? () => onBlur({ target: { name, value } }) : null}
-               onClick={onChange ? () => onChange({ target: { name, value: !value } }) : null}
-               onKeyPress={onChange ? e => {
-                       if (e.key == 'Enter' || e.key == ' ') {
-                               e.preventDefault();
-                               e.stopPropagation();
-                               onChange({ target: { name, value: !value } });
-                       }
-               } : null}
-               tabIndex="0"
-       >
-               <Icon name="check" />
-       </span>;
-};
-
-LargeCheck.propTypes = {
-       className: PropTypes.string,
-       id: PropTypes.string,
-       name: PropTypes.string,
-       onBlur: PropTypes.func,
-       onChange: PropTypes.func,
-       value: PropTypes.bool,
-};
-
-LargeCheck.defaultProps = {
-       className: '',
-       id: '',
-       name: '',
-       onBlur: null,
-       onChange: null,
-       value: false,
-};
-
-export default LargeCheck;
diff --git a/resources/js/components/common/LargeCheck.jsx b/resources/js/components/common/LargeCheck.jsx
new file mode 100644 (file)
index 0000000..9586280
--- /dev/null
@@ -0,0 +1,45 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Icon from './Icon';
+
+const LargeCheck = ({
+       className = '',
+       id = '',
+       name = '',
+       onBlur = null,
+       onChange = null,
+       value = false,
+}) => {
+       let clsn = className ? `${className} custom-check` : 'custom-check';
+       if (value) {
+               clsn += ' checked';
+       }
+       return <span
+               className={clsn}
+               id={id}
+               onBlur={onBlur ? () => onBlur({ target: { name, value } }) : null}
+               onClick={onChange ? () => onChange({ target: { name, value: !value } }) : null}
+               onKeyPress={onChange ? e => {
+                       if (e.key == 'Enter' || e.key == ' ') {
+                               e.preventDefault();
+                               e.stopPropagation();
+                               onChange({ target: { name, value: !value } });
+                       }
+               } : null}
+               tabIndex="0"
+       >
+               <Icon name="check" />
+       </span>;
+};
+
+LargeCheck.propTypes = {
+       className: PropTypes.string,
+       id: PropTypes.string,
+       name: PropTypes.string,
+       onBlur: PropTypes.func,
+       onChange: PropTypes.func,
+       value: PropTypes.bool,
+};
+
+export default LargeCheck;
diff --git a/resources/js/components/common/Loading.js b/resources/js/components/common/Loading.js
deleted file mode 100644 (file)
index b850dec..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react';
-import { ProgressBar } from 'react-bootstrap';
-
-const Loading = () => <div className="loading">
-       <ProgressBar animated now={100} variant="info" />
-</div>;
-
-export default Loading;
diff --git a/resources/js/components/common/Loading.jsx b/resources/js/components/common/Loading.jsx
new file mode 100644 (file)
index 0000000..828c009
--- /dev/null
@@ -0,0 +1,15 @@
+import React from 'react';
+import { ProgressBar } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const Loading = () => {
+       const { t } = useTranslation();
+
+       return <div className="loading">
+               <div className="circle">
+                       <span className="text">{t('general.loading')}</span>
+               </div>
+       </div>;
+};
+
+export default Loading;
diff --git a/resources/js/components/common/PngDialog.js b/resources/js/components/common/PngDialog.js
deleted file mode 100644 (file)
index 1984848..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-
-import Loading from './Loading';
-
-const PngPlayer = React.lazy(() => import('./PngPlayer'));
-
-const PngDialog = ({ onHide, show, src, title }) => <Modal onHide={onHide} show={show} size="lg">
-       {title ?
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {title}
-                       </Modal.Title>
-               </Modal.Header>
-       : null}
-       <Modal.Body>
-               <React.Suspense fallback={<Loading />}>
-                       <PngPlayer src={src} />
-               </React.Suspense>
-       </Modal.Body>
-</Modal>;
-
-PngDialog.propTypes = {
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-       src: PropTypes.string,
-       title: PropTypes.string,
-};
-
-export default PngDialog;
diff --git a/resources/js/components/common/PngDialog.jsx b/resources/js/components/common/PngDialog.jsx
new file mode 100644 (file)
index 0000000..1984848
--- /dev/null
@@ -0,0 +1,31 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+
+import Loading from './Loading';
+
+const PngPlayer = React.lazy(() => import('./PngPlayer'));
+
+const PngDialog = ({ onHide, show, src, title }) => <Modal onHide={onHide} show={show} size="lg">
+       {title ?
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {title}
+                       </Modal.Title>
+               </Modal.Header>
+       : null}
+       <Modal.Body>
+               <React.Suspense fallback={<Loading />}>
+                       <PngPlayer src={src} />
+               </React.Suspense>
+       </Modal.Body>
+</Modal>;
+
+PngDialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+       src: PropTypes.string,
+       title: PropTypes.string,
+};
+
+export default PngDialog;
diff --git a/resources/js/components/common/PngPlayer.js b/resources/js/components/common/PngPlayer.js
deleted file mode 100644 (file)
index 3ecc53c..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-import parseApng from 'apng-js';
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from './Icon';
-
-const createPlayer = async (apng, canvas) => {
-       const context = canvas.getContext('2d', { willReadFrequently: true });
-       const player = await apng.getPlayer(context);
-       player.stop();
-       return player;
-};
-
-const PngPlayer = ({ src }) => {
-       const canvas = React.useRef();
-       const { t } = useTranslation();
-
-       const [apng, setApng] = React.useState(null);
-       const [error, setError] = React.useState(null);
-       const [frameInfo, setFrameInfo] = React.useState('');
-       const [loading, setLoading] = React.useState(true);
-       const [player, setPlayer] = React.useState(null);
-
-       React.useEffect(() => {
-               if (!src) return;
-               setError(null);
-               setLoading(true);
-               const ctrl = new AbortController();
-               const fetchPng = async () => {
-                       try {
-                               const response = await axios.get(src, {
-                                       responseType: 'arraybuffer',
-                                       signal: ctrl.signal,
-                               });
-                               const png = parseApng(response.data);
-                               await png.createImages();
-                               setApng(png);
-                               setLoading(false);
-                       } catch (e) {
-                               if (!axios.isCancel(e)) {
-                                       setError(e);
-                                       console.log(e);
-                               }
-                       }
-               };
-               fetchPng();
-               return () => {
-                       ctrl.abort();
-               };
-       }, [src]);
-
-       React.useEffect(() => {
-               if (loading || !canvas.current) return;
-               setFrameInfo(`1/${apng.frames.length}`);
-               (async () => {
-                       const p = await createPlayer(apng, canvas.current);
-                       setPlayer(p);
-                       const updateFrame = (number) => {
-                               setFrameInfo(`${number + 1}/${apng.frames.length}`);
-                       };
-                       p.on('frame', updateFrame);
-               })();
-       }, [apng, canvas.current, loading]);
-
-       const stop = React.useCallback(() => {
-               if (player) player.stop();
-       }, [player]);
-
-       const toggle = React.useCallback(() => {
-               if (!player) return;
-               if (player.paused) {
-                       player.play();
-               } else {
-                       player.pause();
-               }
-       }, [player]);
-
-       const nextFrame = React.useCallback(() => {
-               if (player) player.renderNextFrame();
-       }, [player]);
-
-       if (error) {
-               return <div>Error</div>;
-       }
-       if (loading) {
-               return <div>Loading</div>;
-       }
-
-       return <div className="png-player">
-               <div className="screen">
-                       <canvas ref={canvas} width={apng.width} height={apng.height} />
-               </div>
-               <span className="ms-auto">{frameInfo}</span>
-               <div className="button-bar controls">
-                       <Button
-                               onClick={stop}
-                               title={t('button.stop')}
-                               variant="outline-secondary"
-                       >
-                               <Icon.STOP title="" />
-                       </Button>
-                       <Button
-                               onClick={toggle}
-                               title={t('button.playPause')}
-                               variant="outline-secondary"
-                       >
-                               <Icon.PLAY title="" />
-                               {' '}
-                               <Icon.PAUSE title="" />
-                       </Button>
-                       <Button
-                               onClick={nextFrame}
-                               title={t('button.nextFrame')}
-                               variant="outline-secondary"
-                       >
-                               <Icon.STEP_FORWARD title="" />
-                       </Button>
-               </div>
-       </div>;
-};
-
-PngPlayer.propTypes = {
-       src: PropTypes.string,
-};
-
-export default PngPlayer;
diff --git a/resources/js/components/common/PngPlayer.jsx b/resources/js/components/common/PngPlayer.jsx
new file mode 100644 (file)
index 0000000..3ecc53c
--- /dev/null
@@ -0,0 +1,129 @@
+import parseApng from 'apng-js';
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from './Icon';
+
+const createPlayer = async (apng, canvas) => {
+       const context = canvas.getContext('2d', { willReadFrequently: true });
+       const player = await apng.getPlayer(context);
+       player.stop();
+       return player;
+};
+
+const PngPlayer = ({ src }) => {
+       const canvas = React.useRef();
+       const { t } = useTranslation();
+
+       const [apng, setApng] = React.useState(null);
+       const [error, setError] = React.useState(null);
+       const [frameInfo, setFrameInfo] = React.useState('');
+       const [loading, setLoading] = React.useState(true);
+       const [player, setPlayer] = React.useState(null);
+
+       React.useEffect(() => {
+               if (!src) return;
+               setError(null);
+               setLoading(true);
+               const ctrl = new AbortController();
+               const fetchPng = async () => {
+                       try {
+                               const response = await axios.get(src, {
+                                       responseType: 'arraybuffer',
+                                       signal: ctrl.signal,
+                               });
+                               const png = parseApng(response.data);
+                               await png.createImages();
+                               setApng(png);
+                               setLoading(false);
+                       } catch (e) {
+                               if (!axios.isCancel(e)) {
+                                       setError(e);
+                                       console.log(e);
+                               }
+                       }
+               };
+               fetchPng();
+               return () => {
+                       ctrl.abort();
+               };
+       }, [src]);
+
+       React.useEffect(() => {
+               if (loading || !canvas.current) return;
+               setFrameInfo(`1/${apng.frames.length}`);
+               (async () => {
+                       const p = await createPlayer(apng, canvas.current);
+                       setPlayer(p);
+                       const updateFrame = (number) => {
+                               setFrameInfo(`${number + 1}/${apng.frames.length}`);
+                       };
+                       p.on('frame', updateFrame);
+               })();
+       }, [apng, canvas.current, loading]);
+
+       const stop = React.useCallback(() => {
+               if (player) player.stop();
+       }, [player]);
+
+       const toggle = React.useCallback(() => {
+               if (!player) return;
+               if (player.paused) {
+                       player.play();
+               } else {
+                       player.pause();
+               }
+       }, [player]);
+
+       const nextFrame = React.useCallback(() => {
+               if (player) player.renderNextFrame();
+       }, [player]);
+
+       if (error) {
+               return <div>Error</div>;
+       }
+       if (loading) {
+               return <div>Loading</div>;
+       }
+
+       return <div className="png-player">
+               <div className="screen">
+                       <canvas ref={canvas} width={apng.width} height={apng.height} />
+               </div>
+               <span className="ms-auto">{frameInfo}</span>
+               <div className="button-bar controls">
+                       <Button
+                               onClick={stop}
+                               title={t('button.stop')}
+                               variant="outline-secondary"
+                       >
+                               <Icon.STOP title="" />
+                       </Button>
+                       <Button
+                               onClick={toggle}
+                               title={t('button.playPause')}
+                               variant="outline-secondary"
+                       >
+                               <Icon.PLAY title="" />
+                               {' '}
+                               <Icon.PAUSE title="" />
+                       </Button>
+                       <Button
+                               onClick={nextFrame}
+                               title={t('button.nextFrame')}
+                               variant="outline-secondary"
+                       >
+                               <Icon.STEP_FORWARD title="" />
+                       </Button>
+               </div>
+       </div>;
+};
+
+PngPlayer.propTypes = {
+       src: PropTypes.string,
+};
+
+export default PngPlayer;
diff --git a/resources/js/components/common/RawHTML.js b/resources/js/components/common/RawHTML.js
deleted file mode 100644 (file)
index dde6d53..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useNavigate } from 'react-router-dom';
-
-import PngDialog from './PngDialog';
-
-const isApng = el => el.nodeName === 'IMG' && el.getAttribute('type') === 'image/apng';
-
-const isLink = el => el.nodeName === 'A';
-
-const canClick = el => {
-       if (isLink(el)) return true;
-       if (isApng(el)) return true;
-       return false;
-};
-
-const RawHTML = ({ html }) => {
-       const navigate = useNavigate();
-       const [apng, setApng] = React.useState(null);
-       const [show, setShow] = React.useState(false);
-       const [title, setTitle] = React.useState(null);
-
-       const onClick = e => {
-               if (e.defaultPrevented) return;
-               if (e.metaKey || e.ctrlKey || e.shiftKey) return;
-               if (e.button !== 0) return;
-
-               let el = e.target;
-               while (el && !canClick(el)) {
-                       el = el.parentNode;
-               }
-               if (!el) return;
-
-               if (isLink(el)) {
-                       if (el.target && el.target !== '_self') return;
-                       if (el.attributes.download) return;
-                       if (el.rel && /(?:^|\s+)external(?:\s+|$)/.test(el.rel)) return;
-
-                       const href = el.getAttribute('href');
-
-                       if (href.startsWith('#')) return;
-                       if (href.startsWith('http')) return;
-                       if (href.startsWith('mailto')) return;
-                       if (href.startsWith('tel')) return;
-
-                       el.blur();
-                       e.preventDefault();
-
-                       setTimeout(() => {
-                               // scroll to top on location change
-                               scrollTo({ top: 0, behavior: 'smooth' });
-                       }, 50);
-
-                       navigate(href);
-                       return;
-               }
-
-               if (isApng(el)) {
-                       setApng(el.getAttribute('src'));
-                       setShow(true);
-                       setTitle(el.getAttribute('alt'));
-               }
-       };
-
-       return <>
-               <div className="raw-html" onClick={onClick} dangerouslySetInnerHTML={{ __html: html }} />
-               <PngDialog onHide={() => setShow(false)} show={show} src={apng} title={title} />
-       </>;
-};
-
-RawHTML.propTypes = {
-       html: PropTypes.string,
-};
-
-export default RawHTML;
diff --git a/resources/js/components/common/RawHTML.jsx b/resources/js/components/common/RawHTML.jsx
new file mode 100644 (file)
index 0000000..dde6d53
--- /dev/null
@@ -0,0 +1,75 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useNavigate } from 'react-router-dom';
+
+import PngDialog from './PngDialog';
+
+const isApng = el => el.nodeName === 'IMG' && el.getAttribute('type') === 'image/apng';
+
+const isLink = el => el.nodeName === 'A';
+
+const canClick = el => {
+       if (isLink(el)) return true;
+       if (isApng(el)) return true;
+       return false;
+};
+
+const RawHTML = ({ html }) => {
+       const navigate = useNavigate();
+       const [apng, setApng] = React.useState(null);
+       const [show, setShow] = React.useState(false);
+       const [title, setTitle] = React.useState(null);
+
+       const onClick = e => {
+               if (e.defaultPrevented) return;
+               if (e.metaKey || e.ctrlKey || e.shiftKey) return;
+               if (e.button !== 0) return;
+
+               let el = e.target;
+               while (el && !canClick(el)) {
+                       el = el.parentNode;
+               }
+               if (!el) return;
+
+               if (isLink(el)) {
+                       if (el.target && el.target !== '_self') return;
+                       if (el.attributes.download) return;
+                       if (el.rel && /(?:^|\s+)external(?:\s+|$)/.test(el.rel)) return;
+
+                       const href = el.getAttribute('href');
+
+                       if (href.startsWith('#')) return;
+                       if (href.startsWith('http')) return;
+                       if (href.startsWith('mailto')) return;
+                       if (href.startsWith('tel')) return;
+
+                       el.blur();
+                       e.preventDefault();
+
+                       setTimeout(() => {
+                               // scroll to top on location change
+                               scrollTo({ top: 0, behavior: 'smooth' });
+                       }, 50);
+
+                       navigate(href);
+                       return;
+               }
+
+               if (isApng(el)) {
+                       setApng(el.getAttribute('src'));
+                       setShow(true);
+                       setTitle(el.getAttribute('alt'));
+               }
+       };
+
+       return <>
+               <div className="raw-html" onClick={onClick} dangerouslySetInnerHTML={{ __html: html }} />
+               <PngDialog onHide={() => setShow(false)} show={show} src={apng} title={title} />
+       </>;
+};
+
+RawHTML.propTypes = {
+       html: PropTypes.string,
+};
+
+export default RawHTML;
diff --git a/resources/js/components/common/Slider.js b/resources/js/components/common/Slider.js
deleted file mode 100644 (file)
index 634c15c..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-const Slider = ({ children, duration, vertical }) => {
-       const [index, setIndex] = React.useState(0);
-
-       React.useEffect(() => {
-               const interval = setInterval(() => {
-                       setIndex(i => (i + 1) % React.Children.count(children));
-               }, duration);
-               return () => {
-                       clearInterval(interval);
-               };
-       }, [React.Children.count(children), duration]);
-
-       return <div className={`slider-container ${vertical ? 'vertical' : 'horizontal'}`}>
-               <div className="slider-slides" style={{
-                       transform: vertical ? `translateY(${-index * 100}%)` : `translateX(${-index * 100}%)`
-               }}>
-                       {children}
-               </div>
-       </div>;
-};
-
-Slider.propTypes = {
-       children: PropTypes.node,
-       duration: PropTypes.number,
-       vertical: PropTypes.bool,
-};
-
-Slider.defaultProps = {
-       duration: 2500,
-};
-
-const Slide = ({ children }) => {
-       return <div className="slider-slide">
-               {children}
-       </div>;
-};
-
-Slide.propTypes = {
-       children: PropTypes.node,
-};
-
-Slider.Slide = Slide;
-
-export default Slider;
diff --git a/resources/js/components/common/Slider.jsx b/resources/js/components/common/Slider.jsx
new file mode 100644 (file)
index 0000000..587fc7f
--- /dev/null
@@ -0,0 +1,43 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+const Slider = ({ children = null, duration = 2500, vertical = false }) => {
+       const [index, setIndex] = React.useState(0);
+
+       React.useEffect(() => {
+               const interval = setInterval(() => {
+                       setIndex(i => (i + 1) % React.Children.count(children));
+               }, duration);
+               return () => {
+                       clearInterval(interval);
+               };
+       }, [React.Children.count(children), duration]);
+
+       return <div className={`slider-container ${vertical ? 'vertical' : 'horizontal'}`}>
+               <div className="slider-slides" style={{
+                       transform: vertical ? `translateY(${-index * 100}%)` : `translateX(${-index * 100}%)`
+               }}>
+                       {children}
+               </div>
+       </div>;
+};
+
+Slider.propTypes = {
+       children: PropTypes.node,
+       duration: PropTypes.number,
+       vertical: PropTypes.bool,
+};
+
+const Slide = ({ children }) => {
+       return <div className="slider-slide">
+               {children}
+       </div>;
+};
+
+Slide.propTypes = {
+       children: PropTypes.node,
+};
+
+Slider.Slide = Slide;
+
+export default Slider;
diff --git a/resources/js/components/common/Spoiler.js b/resources/js/components/common/Spoiler.js
deleted file mode 100644 (file)
index 084de71..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-
-const Spoiler = ({ children }) => {
-       const [show, setShow] = useState(false);
-
-       return <span
-               className={`spoiler ${show ? 'shown' : 'hidden'}`}
-               onClick={() => setShow(true)}
-       >
-               <span className="content">{children}</span>
-       </span>;
-};
-
-Spoiler.propTypes = {
-       children: PropTypes.oneOfType([
-               PropTypes.node,
-               PropTypes.object,
-               PropTypes.string,
-       ]),
-};
-
-export default Spoiler;
diff --git a/resources/js/components/common/Spoiler.jsx b/resources/js/components/common/Spoiler.jsx
new file mode 100644 (file)
index 0000000..084de71
--- /dev/null
@@ -0,0 +1,23 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+
+const Spoiler = ({ children }) => {
+       const [show, setShow] = useState(false);
+
+       return <span
+               className={`spoiler ${show ? 'shown' : 'hidden'}`}
+               onClick={() => setShow(true)}
+       >
+               <span className="content">{children}</span>
+       </span>;
+};
+
+Spoiler.propTypes = {
+       children: PropTypes.oneOfType([
+               PropTypes.node,
+               PropTypes.object,
+               PropTypes.string,
+       ]),
+};
+
+export default Spoiler;
diff --git a/resources/js/components/common/ToggleSwitch.js b/resources/js/components/common/ToggleSwitch.js
deleted file mode 100644 (file)
index db07619..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Icon from './Icon';
-
-const ToggleSwitch = ({
-       isInvalid,
-       isValid,
-       name,
-       offLabel,
-       onBlur,
-       onChange,
-       onLabel,
-       readonly,
-       title,
-       value,
-}) => {
-       const toggle = () => {
-               if (readonly) return;
-               if (onChange) onChange({ target: { name, value: !value } });
-       };
-
-       const handleClick = event => {
-               event.stopPropagation();
-               toggle();
-       };
-
-       const handleKey = event => {
-               if ([13, 32].includes(event.which)) {
-                       toggle();
-                       event.preventDefault();
-                       event.stopPropagation();
-               }
-       };
-
-       const classNames = ['form-control', 'custom-toggle'];
-       if (value) classNames.push('is-toggled');
-       if (isInvalid) classNames.push('is-invalid');
-       if (isValid) classNames.push('is-valid');
-       if (readonly) classNames.push('readonly');
-
-       return <div
-                       className={classNames.join(' ')}
-                       role="button"
-                       aria-pressed={value}
-                       tabIndex="0"
-                       title={title}
-                       onBlur={onBlur ? () => onBlur({ target: { name, value } }) : null}
-                       onClick={handleClick}
-                       onKeyDown={handleKey}
-               >
-                       <div className="handle">
-                               <span className="handle-label">
-                                       {value
-                                               ? onLabel || <Icon name="check" />
-                                               : offLabel || <Icon name="times" />
-                                       }
-                               </span>
-                       </div>
-               </div>;
-};
-
-ToggleSwitch.propTypes = {
-       id: PropTypes.string,
-       isInvalid: PropTypes.bool,
-       isValid: PropTypes.bool,
-       name: PropTypes.string,
-       offLabel: PropTypes.string,
-       onBlur: PropTypes.func,
-       onChange: PropTypes.func,
-       onLabel: PropTypes.string,
-       readonly: PropTypes.bool,
-       title: PropTypes.string,
-       value: PropTypes.bool,
-};
-
-ToggleSwitch.defaultProps = {
-       id: '',
-       isInvalid: false,
-       isValid: false,
-       name: '',
-       offLabel: '',
-       onBlur: null,
-       onChange: null,
-       onLabel: '',
-       readonly: false,
-       title: null,
-       value: false,
-};
-
-export default ToggleSwitch;
diff --git a/resources/js/components/common/ToggleSwitch.jsx b/resources/js/components/common/ToggleSwitch.jsx
new file mode 100644 (file)
index 0000000..98d3d06
--- /dev/null
@@ -0,0 +1,76 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Icon from './Icon';
+
+const ToggleSwitch = ({
+       isInvalid = false,
+       isValid = false,
+       name = '',
+       offLabel = '',
+       onBlur = null,
+       onChange = null,
+       onLabel = null,
+       readonly = false,
+       title = null,
+       value = false,
+}) => {
+       const toggle = () => {
+               if (readonly) return;
+               if (onChange) onChange({ target: { name, value: !value } });
+       };
+
+       const handleClick = event => {
+               event.stopPropagation();
+               toggle();
+       };
+
+       const handleKey = event => {
+               if ([13, 32].includes(event.which)) {
+                       toggle();
+                       event.preventDefault();
+                       event.stopPropagation();
+               }
+       };
+
+       const classNames = ['form-control', 'custom-toggle'];
+       if (value) classNames.push('is-toggled');
+       if (isInvalid) classNames.push('is-invalid');
+       if (isValid) classNames.push('is-valid');
+       if (readonly) classNames.push('readonly');
+
+       return <div
+                       className={classNames.join(' ')}
+                       role="button"
+                       aria-pressed={value}
+                       tabIndex="0"
+                       title={title}
+                       onBlur={onBlur ? () => onBlur({ target: { name, value } }) : null}
+                       onClick={handleClick}
+                       onKeyDown={handleKey}
+               >
+                       <div className="handle">
+                               <span className="handle-label">
+                                       {value
+                                               ? onLabel || <Icon name="check" />
+                                               : offLabel || <Icon name="times" />
+                                       }
+                               </span>
+                       </div>
+               </div>;
+};
+
+ToggleSwitch.propTypes = {
+       isInvalid: PropTypes.bool,
+       isValid: PropTypes.bool,
+       name: PropTypes.string,
+       offLabel: PropTypes.string,
+       onBlur: PropTypes.func,
+       onChange: PropTypes.func,
+       onLabel: PropTypes.string,
+       readonly: PropTypes.bool,
+       title: PropTypes.string,
+       value: PropTypes.bool,
+};
+
+export default ToggleSwitch;
diff --git a/resources/js/components/common/UserSelect.js b/resources/js/components/common/UserSelect.js
deleted file mode 100644 (file)
index 03aa097..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React, { useCallback, useEffect, useRef, useState } from 'react';
-import { Button, Form, ListGroup } from 'react-bootstrap';
-
-import Icon from '../common/Icon';
-import UserBox from '../users/Box';
-import debounce from '../../helpers/debounce';
-
-const UserSelect = ({ name, onChange, value }) => {
-       const [resolved, setResolved] = useState(null);
-       const [results, setResults] = useState([]);
-       const [search, setSearch] = useState('');
-       const [showResults, setShowResults] = useState(false);
-
-       const ref = useRef(null);
-
-       useEffect(() => {
-               const handleEventOutside = e => {
-                       if (ref.current && !ref.current.contains(e.target)) {
-                               setShowResults(false);
-                       }
-               };
-               document.addEventListener('click', handleEventOutside, true);
-               document.addEventListener('focus', handleEventOutside, true);
-               return () => {
-                       document.removeEventListener('click', handleEventOutside, true);
-                       document.removeEventListener('focus', handleEventOutside, true);
-               };
-       }, []);
-
-       let ctrl = null;
-       const fetch = useCallback(debounce(async phrase => {
-               if (ctrl) {
-                       ctrl.abort();
-               }
-               ctrl = new AbortController();
-               if (!phrase || phrase.length < 3) {
-                       setResults([]);
-                       return;
-               }
-               try {
-                       const response = await axios.get(`/api/users`, {
-                               params: {
-                                       phrase,
-                               },
-                               signal: ctrl.signal,
-                       });
-                       ctrl = null;
-                       setResults(response.data);
-               } catch (e) {
-                       ctrl = null;
-                       console.error(e);
-               }
-       }, 300), []);
-
-       useEffect(() => {
-               fetch(search);
-       }, [search]);
-
-       useEffect(() => {
-               if (value) {
-                       axios
-                               .get(`/api/users/${value}`)
-                       .then(response => {
-                               setResolved(response.data);
-                       });
-               } else {
-                       setResolved(null);
-               }
-       }, [value]);
-
-       if (value) {
-               return <div className="d-flex justify-content-between">
-                       {resolved ? <UserBox discriminator noLink user={resolved} /> : <span>value</span>}
-                       <Button
-                               onClick={() => onChange({ target: { name, value: null }})}
-                               size="sm"
-                               variant="outline-danger"
-                       >
-                               <Icon.REMOVE />
-                       </Button>
-               </div>;
-       }
-       return <div className={`user-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
-               <Form.Control
-                       className="search-input"
-                       name={Math.random().toString(20).substr(2, 10)}
-                       onChange={e => setSearch(e.target.value)}
-                       onFocus={() => setShowResults(true)}
-                       type="search"
-                       value={search}
-               />
-               <div className="search-results-holder">
-                       <ListGroup className="search-results">
-                               {results.map(result =>
-                                       <ListGroup.Item
-                                               action
-                                               key={result.id}
-                                               onClick={() => onChange({
-                                                       target: { name, value: result.id },
-                                               })}
-                                       >
-                                               <UserBox discriminator noLink user={result} />
-                                       </ListGroup.Item>
-                               )}
-                       </ListGroup>
-               </div>
-       </div>;
-};
-
-UserSelect.propTypes = {
-       name: PropTypes.string,
-       onChange: PropTypes.func,
-       value: PropTypes.string,
-};
-
-export default UserSelect;
diff --git a/resources/js/components/common/UserSelect.jsx b/resources/js/components/common/UserSelect.jsx
new file mode 100644 (file)
index 0000000..32bd186
--- /dev/null
@@ -0,0 +1,118 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React, { useCallback, useEffect, useRef, useState } from 'react';
+import { Button, Form, ListGroup } from 'react-bootstrap';
+
+import Icon from '../common/Icon';
+import UserBox from '../users/Box';
+import debounce from '../../helpers/debounce';
+
+const UserSelect = ({ name, onChange, value }) => {
+       const [resolved, setResolved] = useState(null);
+       const [results, setResults] = useState([]);
+       const [search, setSearch] = useState('');
+       const [showResults, setShowResults] = useState(false);
+
+       const ref = useRef(null);
+
+       useEffect(() => {
+               const handleEventOutside = e => {
+                       if (ref.current && !ref.current.contains(e.target)) {
+                               setShowResults(false);
+                       }
+               };
+               document.addEventListener('mousedown', handleEventOutside, true);
+               document.addEventListener('focus', handleEventOutside, true);
+               return () => {
+                       document.removeEventListener('mousedown', handleEventOutside, true);
+                       document.removeEventListener('focus', handleEventOutside, true);
+               };
+       }, []);
+
+       let ctrl = null;
+       const fetch = useCallback(debounce(async phrase => {
+               if (ctrl) {
+                       ctrl.abort();
+               }
+               ctrl = new AbortController();
+               if (!phrase || phrase.length < 3) {
+                       setResults([]);
+                       return;
+               }
+               try {
+                       const response = await axios.get(`/api/users`, {
+                               params: {
+                                       phrase,
+                               },
+                               signal: ctrl.signal,
+                       });
+                       ctrl = null;
+                       setResults(response.data);
+               } catch (e) {
+                       ctrl = null;
+                       console.error(e);
+               }
+       }, 300), []);
+
+       useEffect(() => {
+               fetch(search);
+       }, [search]);
+
+       useEffect(() => {
+               if (value) {
+                       axios
+                               .get(`/api/users/${value}`)
+                       .then(response => {
+                               setResolved(response.data);
+                       });
+               } else {
+                       setResolved(null);
+               }
+       }, [value]);
+
+       if (value) {
+               return <div className="d-flex justify-content-between">
+                       {resolved ? <UserBox discriminator noLink user={resolved} /> : <span>value</span>}
+                       <Button
+                               onClick={() => onChange({ target: { name, value: null }})}
+                               size="sm"
+                               variant="outline-danger"
+                       >
+                               <Icon.REMOVE />
+                       </Button>
+               </div>;
+       }
+       return <div className={`user-select ${showResults ? 'expanded' : 'collapsed'}`} ref={ref}>
+               <Form.Control
+                       className="search-input"
+                       name={Math.random().toString(20).substr(2, 10)}
+                       onChange={e => setSearch(e.target.value)}
+                       onFocus={() => setShowResults(true)}
+                       type="search"
+                       value={search}
+               />
+               <div className="search-results-holder">
+                       <ListGroup className="search-results">
+                               {results.map(result =>
+                                       <ListGroup.Item
+                                               action
+                                               key={result.id}
+                                               onClick={() => onChange({
+                                                       target: { name, value: result.id },
+                                               })}
+                                       >
+                                               <UserBox discriminator noLink user={result} />
+                                       </ListGroup.Item>
+                               )}
+                       </ListGroup>
+               </div>
+       </div>;
+};
+
+UserSelect.propTypes = {
+       name: PropTypes.string,
+       onChange: PropTypes.func,
+       value: PropTypes.string,
+};
+
+export default UserSelect;
diff --git a/resources/js/components/common/ZeldaIcon.js b/resources/js/components/common/ZeldaIcon.js
deleted file mode 100644 (file)
index 18b13eb..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-import Icon from './Icon';
-
-const ITEM_MAP = [
-    'aga',
-    'armos',
-    'arrghus',
-    'big-key',
-    'blind',
-    'blue-boomerang',
-    'blue-mail',
-    'blue-pendant',
-    'blue-potion',
-    'bombos',
-    'bomb',
-    'book',
-    'boots',
-    'bottle-bee',
-    'bottle-good-bee',
-    'bottle',
-    'bowless-silvers',
-    'bow',
-    'bugnet',
-    'bunny-head',
-    'byrna',
-    'cape',
-    'chest',
-    'compass',
-    'crystal',
-    'crystal-switch-blue',
-    'crystal-switch',
-    'crystal-switch-red',
-    'duck',
-    'ether',
-    'fairy',
-    'fighter-shield',
-    'fighter-sword',
-    'fire-rod',
-    'fire-shield',
-    'flippers',
-    'flute',
-    'ganon',
-    'glove',
-    'gold-sword',
-    'green-mail',
-    'green-pendant',
-    'green-potion',
-    'gt',
-    'half-magic',
-    'hammer',
-    'heart-0',
-    'heart-1',
-    'heart-2',
-    'heart-3',
-    'heart-container',
-    'heart-piece',
-    'helma',
-    'hookshot',
-    'ice-rod',
-    'kholdstare',
-    'lamp',
-    'lanmolas',
-    'link-head',
-    'map',
-    'master-sword',
-    'mirror',
-    'mirror-shield',
-    'mitts',
-    'moldorm',
-    'moonpearl',
-    'mothula',
-    'mushroom',
-    'open-chest',
-    'powder',
-    'quake',
-    'quarter-magic',
-    'red-bomb',
-    'red-boomerang',
-    'red-crystal',
-    'red-mail',
-    'red-pendant',
-    'red-potion',
-    'shovel',
-    'silvers',
-    'small-key',
-    'somaria',
-    'sword-1',
-    'sword-2',
-    'sword-3',
-    'sword-4',
-    'tempered-sword',
-    'triforce-piece',
-    'triforce',
-    'trinexx',
-    'vitreous',
-];
-
-const ITEM_MAP_WIDTH = 8;
-
-const ITEM_MAP_HEIGHT = Math.ceil(ITEM_MAP.length / ITEM_MAP_WIDTH);
-
-const ITEM_MAP_URL = '/items-v2.png';
-
-const isOnItemMap = name => ITEM_MAP.includes(name);
-
-const getItemMapX = name => ITEM_MAP.indexOf(name) % ITEM_MAP_WIDTH;
-
-const getItemMapY = name => Math.floor(ITEM_MAP.indexOf(name) / ITEM_MAP_WIDTH);
-
-const getItemMapStyle = name => {
-       const x = getItemMapX(name);
-       const y = getItemMapY(name);
-       return {
-               backgroundImage: `url(${ITEM_MAP_URL})`,
-               backgroundPosition: `-${x * 100}% -${y * 100}%`,
-               backgroundSize: `${ITEM_MAP_WIDTH * 100}% ${ITEM_MAP_HEIGHT * 100}%`,
-       };
-};
-
-const getIconURL = name => {
-       switch (name) {
-               case 'dungeon-ct':
-               case 'dungeon-dp':
-               case 'dungeon-ep':
-               case 'dungeon-gt':
-               case 'dungeon-hc':
-               case 'dungeon-ip':
-               case 'dungeon-mm':
-               case 'dungeon-pd':
-               case 'dungeon-sp':
-               case 'dungeon-sw':
-               case 'dungeon-th':
-               case 'dungeon-tr':
-               case 'dungeon-tt':
-                       return `/dungeon/${name.substr(8)}.png`;
-               default:
-                       return '';
-       }
-};
-
-const isHalfWidth = name => [
-       'blue-boomerang',
-       'fire-rod',
-       'ice-rod',
-       'hookshot',
-       'red-boomerang',
-].includes(name);
-
-const ZeldaIcon = ({ name, svg, title }) => {
-       const { t } = useTranslation();
-
-       const invert = name.startsWith('not-');
-       const strippedName = invert ? name.substr(4) : name;
-       const src = getIconURL(strippedName);
-       const alt = t(`icon.zelda.${name}`);
-       const realTitle = title !== '' ? title || alt : null;
-
-       if (svg) {
-               const clipX = getItemMapX(strippedName);
-               const clipY = getItemMapY(strippedName);
-               const cropX = isHalfWidth(strippedName) ? 0.25 : 0.02;
-               const cropY = 0.02;
-               const cropW = 1 - (2 * cropX);
-               const cropH = 1 - (2 * cropY);
-               return <image
-                       href={isOnItemMap(strippedName) ? ITEM_MAP_URL : src}
-                       width={ITEM_MAP_WIDTH}
-                       height={ITEM_MAP_HEIGHT}
-                       x={`-${clipX + 0.5}`}
-                       y={`-${clipY + 0.5}`}
-                       clipPath={`xywh(${clipX + cropX} ${clipY + cropY} ${cropW} ${cropH})`}
-               >
-                       {realTitle ?
-                               <title>{realTitle}</title>
-                       : null}
-               </image>;
-       }
-
-       return <span className="zelda-icon">
-               {isOnItemMap(strippedName) ?
-                       <span
-                               className="item-map-icon"
-                               style={getItemMapStyle(strippedName)}
-                               title={realTitle}
-                       />
-               : null}
-               {src ?
-                       <img
-                               alt={alt}
-                               src={src}
-                               title={realTitle}
-                       />
-               : null}
-               {invert ?
-                       <span className="strike">
-                               <Icon.SLASH title="" />
-                       </span>
-               : null}
-       </span>;
-};
-
-ZeldaIcon.propTypes = {
-       name: PropTypes.string.isRequired,
-       svg: PropTypes.bool,
-       title: PropTypes.string,
-};
-
-export default ZeldaIcon;
diff --git a/resources/js/components/common/ZeldaIcon.jsx b/resources/js/components/common/ZeldaIcon.jsx
new file mode 100644 (file)
index 0000000..18b13eb
--- /dev/null
@@ -0,0 +1,211 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import Icon from './Icon';
+
+const ITEM_MAP = [
+    'aga',
+    'armos',
+    'arrghus',
+    'big-key',
+    'blind',
+    'blue-boomerang',
+    'blue-mail',
+    'blue-pendant',
+    'blue-potion',
+    'bombos',
+    'bomb',
+    'book',
+    'boots',
+    'bottle-bee',
+    'bottle-good-bee',
+    'bottle',
+    'bowless-silvers',
+    'bow',
+    'bugnet',
+    'bunny-head',
+    'byrna',
+    'cape',
+    'chest',
+    'compass',
+    'crystal',
+    'crystal-switch-blue',
+    'crystal-switch',
+    'crystal-switch-red',
+    'duck',
+    'ether',
+    'fairy',
+    'fighter-shield',
+    'fighter-sword',
+    'fire-rod',
+    'fire-shield',
+    'flippers',
+    'flute',
+    'ganon',
+    'glove',
+    'gold-sword',
+    'green-mail',
+    'green-pendant',
+    'green-potion',
+    'gt',
+    'half-magic',
+    'hammer',
+    'heart-0',
+    'heart-1',
+    'heart-2',
+    'heart-3',
+    'heart-container',
+    'heart-piece',
+    'helma',
+    'hookshot',
+    'ice-rod',
+    'kholdstare',
+    'lamp',
+    'lanmolas',
+    'link-head',
+    'map',
+    'master-sword',
+    'mirror',
+    'mirror-shield',
+    'mitts',
+    'moldorm',
+    'moonpearl',
+    'mothula',
+    'mushroom',
+    'open-chest',
+    'powder',
+    'quake',
+    'quarter-magic',
+    'red-bomb',
+    'red-boomerang',
+    'red-crystal',
+    'red-mail',
+    'red-pendant',
+    'red-potion',
+    'shovel',
+    'silvers',
+    'small-key',
+    'somaria',
+    'sword-1',
+    'sword-2',
+    'sword-3',
+    'sword-4',
+    'tempered-sword',
+    'triforce-piece',
+    'triforce',
+    'trinexx',
+    'vitreous',
+];
+
+const ITEM_MAP_WIDTH = 8;
+
+const ITEM_MAP_HEIGHT = Math.ceil(ITEM_MAP.length / ITEM_MAP_WIDTH);
+
+const ITEM_MAP_URL = '/items-v2.png';
+
+const isOnItemMap = name => ITEM_MAP.includes(name);
+
+const getItemMapX = name => ITEM_MAP.indexOf(name) % ITEM_MAP_WIDTH;
+
+const getItemMapY = name => Math.floor(ITEM_MAP.indexOf(name) / ITEM_MAP_WIDTH);
+
+const getItemMapStyle = name => {
+       const x = getItemMapX(name);
+       const y = getItemMapY(name);
+       return {
+               backgroundImage: `url(${ITEM_MAP_URL})`,
+               backgroundPosition: `-${x * 100}% -${y * 100}%`,
+               backgroundSize: `${ITEM_MAP_WIDTH * 100}% ${ITEM_MAP_HEIGHT * 100}%`,
+       };
+};
+
+const getIconURL = name => {
+       switch (name) {
+               case 'dungeon-ct':
+               case 'dungeon-dp':
+               case 'dungeon-ep':
+               case 'dungeon-gt':
+               case 'dungeon-hc':
+               case 'dungeon-ip':
+               case 'dungeon-mm':
+               case 'dungeon-pd':
+               case 'dungeon-sp':
+               case 'dungeon-sw':
+               case 'dungeon-th':
+               case 'dungeon-tr':
+               case 'dungeon-tt':
+                       return `/dungeon/${name.substr(8)}.png`;
+               default:
+                       return '';
+       }
+};
+
+const isHalfWidth = name => [
+       'blue-boomerang',
+       'fire-rod',
+       'ice-rod',
+       'hookshot',
+       'red-boomerang',
+].includes(name);
+
+const ZeldaIcon = ({ name, svg, title }) => {
+       const { t } = useTranslation();
+
+       const invert = name.startsWith('not-');
+       const strippedName = invert ? name.substr(4) : name;
+       const src = getIconURL(strippedName);
+       const alt = t(`icon.zelda.${name}`);
+       const realTitle = title !== '' ? title || alt : null;
+
+       if (svg) {
+               const clipX = getItemMapX(strippedName);
+               const clipY = getItemMapY(strippedName);
+               const cropX = isHalfWidth(strippedName) ? 0.25 : 0.02;
+               const cropY = 0.02;
+               const cropW = 1 - (2 * cropX);
+               const cropH = 1 - (2 * cropY);
+               return <image
+                       href={isOnItemMap(strippedName) ? ITEM_MAP_URL : src}
+                       width={ITEM_MAP_WIDTH}
+                       height={ITEM_MAP_HEIGHT}
+                       x={`-${clipX + 0.5}`}
+                       y={`-${clipY + 0.5}`}
+                       clipPath={`xywh(${clipX + cropX} ${clipY + cropY} ${cropW} ${cropH})`}
+               >
+                       {realTitle ?
+                               <title>{realTitle}</title>
+                       : null}
+               </image>;
+       }
+
+       return <span className="zelda-icon">
+               {isOnItemMap(strippedName) ?
+                       <span
+                               className="item-map-icon"
+                               style={getItemMapStyle(strippedName)}
+                               title={realTitle}
+                       />
+               : null}
+               {src ?
+                       <img
+                               alt={alt}
+                               src={src}
+                               title={realTitle}
+                       />
+               : null}
+               {invert ?
+                       <span className="strike">
+                               <Icon.SLASH title="" />
+                       </span>
+               : null}
+       </span>;
+};
+
+ZeldaIcon.propTypes = {
+       name: PropTypes.string.isRequired,
+       svg: PropTypes.bool,
+       title: PropTypes.string,
+};
+
+export default ZeldaIcon;
diff --git a/resources/js/components/discord-bot/ChannelControls.jsx b/resources/js/components/discord-bot/ChannelControls.jsx
new file mode 100644 (file)
index 0000000..ee06e66
--- /dev/null
@@ -0,0 +1,65 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+const ChannelControls = ({ channel, guild }) => {
+       const [messageText, setMessageText] = React.useState('');
+
+       const { t } = useTranslation();
+
+       const sendMessage = React.useCallback(async (text) => {
+               try {
+                       await axios.post(`/api/discord-bot/${guild.id}/send-message`, {
+                               channel: channel.id,
+                               text,
+                       });
+                       toastr.success(t('discordBot.messageSuccess'));
+               } catch (e) {
+                       toastr.error(t('discordBot.messageError'));
+               }
+       }, [channel, guild]);
+
+       return <section className="mt-5">
+               <h3>{t('discordBot.channelControls')}</h3>
+               <Row>
+                       <Col md={6}>
+                               <Form.Group>
+                                       <Form.Label>{t('discordBot.message')}</Form.Label>
+                                       <Form.Control
+                                               as="textarea"
+                                               onChange={({ target: { value } }) => {
+                                                       setMessageText(value);
+                                               }}
+                                               value={messageText}
+                                       />
+                                       <div className="button-bar">
+                                               <Button
+                                                       className="mt-2"
+                                                       disabled={!messageText}
+                                                       onClick={() => {
+                                                               if (messageText) sendMessage(messageText);
+                                                       }}
+                                                       variant="discord"
+                                               >
+                                                       {t('discordBot.sendMessage')}
+                                               </Button>
+                                       </div>
+                               </Form.Group>
+                       </Col>
+               </Row>
+       </section>;
+};
+
+ChannelControls.propTypes = {
+       channel: PropTypes.shape({
+               id: PropTypes.number,
+       }),
+       guild: PropTypes.shape({
+               id: PropTypes.number,
+       }),
+};
+
+export default ChannelControls;
diff --git a/resources/js/components/discord-bot/Controls.js b/resources/js/components/discord-bot/Controls.js
deleted file mode 100644 (file)
index 408e314..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import { Col, Form, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import DiscordChannelSelect from '../common/DiscordChannelSelect';
-import DiscordSelect from '../common/DiscordSelect';
-
-const Controls = () => {
-       const [channel, setChannel] = React.useState('');
-       const [guild, setGuild] = React.useState(null);
-
-       const { t } = useTranslation();
-
-       return <>
-               <Row>
-                       <Form.Group as={Col} md={6}>
-                               <Form.Label>{t('discordBot.guild')}</Form.Label>
-                               <Form.Control
-                                       as={DiscordSelect}
-                                       onChange={({ guild }) => { setGuild(guild); setChannel(''); }}
-                                       value={guild ? guild.guild_id : ''}
-                               />
-                       </Form.Group>
-                       <Form.Group as={Col} md={6}>
-                               <Form.Label>{t('discordBot.channel')}</Form.Label>
-                               {guild ?
-                                       <Form.Control
-                                               as={DiscordChannelSelect}
-                                               guild={guild.guild_id}
-                                               onChange={({ target: { value } }) => setChannel(value)}
-                                               types={[]}
-                                               value={channel}
-                                       />
-                               :
-                                       <Form.Control plaintext readOnly defaultValue={t('discordBot.selectGuild')} />
-                               }
-                       </Form.Group>
-               </Row>
-       </>;
-};
-
-export default Controls;
diff --git a/resources/js/components/discord-bot/Controls.jsx b/resources/js/components/discord-bot/Controls.jsx
new file mode 100644 (file)
index 0000000..12c2fb6
--- /dev/null
@@ -0,0 +1,46 @@
+import React from 'react';
+import { Col, Form, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import ChannelControls from './ChannelControls';
+import DiscordChannelSelect from '../common/DiscordChannelSelect';
+import DiscordSelect from '../common/DiscordSelect';
+
+const Controls = () => {
+       const [channel, setChannel] = React.useState(null);
+       const [guild, setGuild] = React.useState(null);
+
+       const { t } = useTranslation();
+
+       return <>
+               <Row>
+                       <Form.Group as={Col} md={6}>
+                               <Form.Label>{t('discordBot.guild')}</Form.Label>
+                               <Form.Control
+                                       as={DiscordSelect}
+                                       onChange={({ guild }) => { setGuild(guild); setChannel(''); }}
+                                       value={guild ? guild.guild_id : ''}
+                               />
+                       </Form.Group>
+                       <Form.Group as={Col} md={6}>
+                               <Form.Label>{t('discordBot.channel')}</Form.Label>
+                               {guild ?
+                                       <Form.Control
+                                               as={DiscordChannelSelect}
+                                               guild={guild.guild_id}
+                                               onChange={({ channel }) => setChannel(channel)}
+                                               types={[]}
+                                               value={channel ? channel.channel_id : ''}
+                                       />
+                               :
+                                       <Form.Control plaintext readOnly defaultValue={t('discordBot.selectGuild')} />
+                               }
+                       </Form.Group>
+               </Row>
+               {guild && channel ?
+                       <ChannelControls channel={channel} guild={guild} />
+               : null}
+       </>;
+};
+
+export default Controls;
diff --git a/resources/js/components/discord-guilds/Box.js b/resources/js/components/discord-guilds/Box.js
deleted file mode 100644 (file)
index dcfff9e..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-const getIconUrl = guild =>
-       `https://cdn.discordapp.com/icons/${guild.guild_id}/${guild.icon_hash}.png`;
-
-const Box = ({ guild }) => <div className="guild-box">
-               <img alt="" src={getIconUrl(guild)} />
-               <span>{guild.name}</span>
-       </div>;
-
-Box.propTypes = {
-       guild: PropTypes.shape({
-               guild_id: PropTypes.string,
-               icon_hash: PropTypes.string,
-               name: PropTypes.string,
-       }),
-};
-
-export default Box;
diff --git a/resources/js/components/discord-guilds/Box.jsx b/resources/js/components/discord-guilds/Box.jsx
new file mode 100644 (file)
index 0000000..dcfff9e
--- /dev/null
@@ -0,0 +1,20 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+const getIconUrl = guild =>
+       `https://cdn.discordapp.com/icons/${guild.guild_id}/${guild.icon_hash}.png`;
+
+const Box = ({ guild }) => <div className="guild-box">
+               <img alt="" src={getIconUrl(guild)} />
+               <span>{guild.name}</span>
+       </div>;
+
+Box.propTypes = {
+       guild: PropTypes.shape({
+               guild_id: PropTypes.string,
+               icon_hash: PropTypes.string,
+               name: PropTypes.string,
+       }),
+};
+
+export default Box;
diff --git a/resources/js/components/discord-guilds/ChannelBox.js b/resources/js/components/discord-guilds/ChannelBox.js
deleted file mode 100644 (file)
index 9b75fad..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Icon from '../common/Icon';
-
-const getIcon = channel => {
-       if (channel.type === 0) {
-               return <Icon.HASH title="" />;
-       }
-       if (channel.type === 2) {
-               return <Icon.VOLUME title="" />;
-       }
-       return null;
-};
-
-const Box = ({ channel }) => <div className="channel-box">
-       {getIcon(channel)}
-       <span>{channel.name}</span>
-</div>;
-
-Box.propTypes = {
-       channel: PropTypes.shape({
-               name: PropTypes.string,
-       }),
-};
-
-export default Box;
diff --git a/resources/js/components/discord-guilds/ChannelBox.jsx b/resources/js/components/discord-guilds/ChannelBox.jsx
new file mode 100644 (file)
index 0000000..9b75fad
--- /dev/null
@@ -0,0 +1,27 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Icon from '../common/Icon';
+
+const getIcon = channel => {
+       if (channel.type === 0) {
+               return <Icon.HASH title="" />;
+       }
+       if (channel.type === 2) {
+               return <Icon.VOLUME title="" />;
+       }
+       return null;
+};
+
+const Box = ({ channel }) => <div className="channel-box">
+       {getIcon(channel)}
+       <span>{channel.name}</span>
+</div>;
+
+Box.propTypes = {
+       channel: PropTypes.shape({
+               name: PropTypes.string,
+       }),
+};
+
+export default Box;
diff --git a/resources/js/components/episodes/ApplyDialog.js b/resources/js/components/episodes/ApplyDialog.js
deleted file mode 100644 (file)
index 5f0422e..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import ApplyForm from './ApplyForm';
-
-const ApplyDialog = ({
-       as,
-       episode,
-       onHide,
-       onSubmit,
-       show,
-}) => {
-       const { t } = useTranslation();
-
-       return <Modal className="apply-dialog" onHide={onHide} show={show}>
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {t('episodes.applyDialog.title')}
-                       </Modal.Title>
-               </Modal.Header>
-               <ApplyForm
-                       as={as}
-                       episode={episode}
-                       onCancel={onHide}
-                       onSubmit={onSubmit}
-               />
-       </Modal>;
-};
-
-ApplyDialog.propTypes = {
-       as: PropTypes.string,
-       episode: PropTypes.shape({
-       }),
-       onHide: PropTypes.func,
-       onSubmit: PropTypes.func,
-       show: PropTypes.bool,
-};
-
-export default ApplyDialog;
diff --git a/resources/js/components/episodes/ApplyDialog.jsx b/resources/js/components/episodes/ApplyDialog.jsx
new file mode 100644 (file)
index 0000000..5f0422e
--- /dev/null
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import ApplyForm from './ApplyForm';
+
+const ApplyDialog = ({
+       as,
+       episode,
+       onHide,
+       onSubmit,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal className="apply-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('episodes.applyDialog.title')}
+                       </Modal.Title>
+               </Modal.Header>
+               <ApplyForm
+                       as={as}
+                       episode={episode}
+                       onCancel={onHide}
+                       onSubmit={onSubmit}
+               />
+       </Modal>;
+};
+
+ApplyDialog.propTypes = {
+       as: PropTypes.string,
+       episode: PropTypes.shape({
+       }),
+       onHide: PropTypes.func,
+       onSubmit: PropTypes.func,
+       show: PropTypes.bool,
+};
+
+export default ApplyDialog;
diff --git a/resources/js/components/episodes/ApplyForm.js b/resources/js/components/episodes/ApplyForm.js
deleted file mode 100644 (file)
index ce5f88e..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Form, Modal } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import DialogEpisode from './DialogEpisode';
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import { applicableChannels } from '../../helpers/permissions';
-import { withUser } from '../../hooks/user';
-
-const ApplyForm = ({
-       as,
-       episode,
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       touched,
-       user,
-       values,
-}) => {
-       const { t } = useTranslation();
-
-       const available_channels = React.useMemo(() => {
-               return applicableChannels(user, episode, as);
-       }, [as, episode, user]);
-
-       return <Form noValidate onSubmit={handleSubmit}>
-               <Modal.Body>
-                       <DialogEpisode episode={episode} />
-                       <Form.Group controlId="apply.role">
-                               <Form.Label>{t('episodes.applyDialog.signUpAs')}</Form.Label>
-                               <Form.Control
-                                       plaintext
-                                       readOnly
-                                       value={t(`crew.roles.${as}`)}
-                               />
-                       </Form.Group>
-                       <Form.Group controlId="apply.channel_id">
-                               <Form.Label>{t('episodes.channel')}</Form.Label>
-                               <Form.Select
-                                       isInvalid={!!(touched.channel_id && errors.channel_id)}
-                                       name="channel_id"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.channel_id || 0}
-                               >
-                                       <option disabled value={0}>{t('general.pleaseSelect')}</option>
-                                       {available_channels.map(c =>
-                                               <option key={c.id} value={c.id}>
-                                                       {c.title}
-                                               </option>
-                                       )}
-                               </Form.Select>
-                               {touched.channel_id && errors.channel_id ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.channel_id)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Modal.Body>
-               <Modal.Footer>
-                       {onCancel ?
-                               <Button onClick={onCancel} variant="secondary">
-                                       {t('button.cancel')}
-                               </Button>
-                       : null}
-                       <Button type="submit" variant="primary">
-                               {t('button.submit')}
-                       </Button>
-               </Modal.Footer>
-       </Form>;
-};
-
-ApplyForm.propTypes = {
-       as: PropTypes.string,
-       episode: PropTypes.shape({
-       }),
-       errors: PropTypes.shape({
-               channel_id: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               channel_id: PropTypes.bool,
-       }),
-       user: PropTypes.shape({
-       }),
-       values: PropTypes.shape({
-               channel_id: PropTypes.number,
-       }),
-};
-
-export default withUser(withFormik({
-       displayName: 'ApplyForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { setErrors } = actions;
-               const { onSubmit } = actions.props;
-               try {
-                       await onSubmit(values);
-               } catch (e) {
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ as, episode, user }) => {
-               const channels = applicableChannels(user, episode, as);
-               return {
-                       as,
-                       channel_id: channels.length ? channels[0].id : 0,
-                       episode_id: episode ? episode.id : 0,
-               };
-       },
-})(ApplyForm));
diff --git a/resources/js/components/episodes/ApplyForm.jsx b/resources/js/components/episodes/ApplyForm.jsx
new file mode 100644 (file)
index 0000000..ce5f88e
--- /dev/null
@@ -0,0 +1,120 @@
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Form, Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import DialogEpisode from './DialogEpisode';
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import { applicableChannels } from '../../helpers/permissions';
+import { withUser } from '../../hooks/user';
+
+const ApplyForm = ({
+       as,
+       episode,
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       touched,
+       user,
+       values,
+}) => {
+       const { t } = useTranslation();
+
+       const available_channels = React.useMemo(() => {
+               return applicableChannels(user, episode, as);
+       }, [as, episode, user]);
+
+       return <Form noValidate onSubmit={handleSubmit}>
+               <Modal.Body>
+                       <DialogEpisode episode={episode} />
+                       <Form.Group controlId="apply.role">
+                               <Form.Label>{t('episodes.applyDialog.signUpAs')}</Form.Label>
+                               <Form.Control
+                                       plaintext
+                                       readOnly
+                                       value={t(`crew.roles.${as}`)}
+                               />
+                       </Form.Group>
+                       <Form.Group controlId="apply.channel_id">
+                               <Form.Label>{t('episodes.channel')}</Form.Label>
+                               <Form.Select
+                                       isInvalid={!!(touched.channel_id && errors.channel_id)}
+                                       name="channel_id"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.channel_id || 0}
+                               >
+                                       <option disabled value={0}>{t('general.pleaseSelect')}</option>
+                                       {available_channels.map(c =>
+                                               <option key={c.id} value={c.id}>
+                                                       {c.title}
+                                               </option>
+                                       )}
+                               </Form.Select>
+                               {touched.channel_id && errors.channel_id ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.channel_id)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Modal.Body>
+               <Modal.Footer>
+                       {onCancel ?
+                               <Button onClick={onCancel} variant="secondary">
+                                       {t('button.cancel')}
+                               </Button>
+                       : null}
+                       <Button type="submit" variant="primary">
+                               {t('button.submit')}
+                       </Button>
+               </Modal.Footer>
+       </Form>;
+};
+
+ApplyForm.propTypes = {
+       as: PropTypes.string,
+       episode: PropTypes.shape({
+       }),
+       errors: PropTypes.shape({
+               channel_id: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               channel_id: PropTypes.bool,
+       }),
+       user: PropTypes.shape({
+       }),
+       values: PropTypes.shape({
+               channel_id: PropTypes.number,
+       }),
+};
+
+export default withUser(withFormik({
+       displayName: 'ApplyForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { setErrors } = actions;
+               const { onSubmit } = actions.props;
+               try {
+                       await onSubmit(values);
+               } catch (e) {
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ as, episode, user }) => {
+               const channels = applicableChannels(user, episode, as);
+               return {
+                       as,
+                       channel_id: channels.length ? channels[0].id : 0,
+                       episode_id: episode ? episode.id : 0,
+               };
+       },
+})(ApplyForm));
diff --git a/resources/js/components/episodes/Channel.js b/resources/js/components/episodes/Channel.js
deleted file mode 100644 (file)
index e2d25d7..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-
-import Icon from '../common/Icon';
-import { mayEditRestream } from '../../helpers/permissions';
-import { useUser } from '../../hooks/user';
-
-const Channel = ({ channel, episode, onEditRestream }) => {
-       const { user } = useUser();
-
-       return <div className="episode-channel text-nowrap">
-               <Button
-                       href={channel.stream_link}
-                       rel="noreferer"
-                       target="_blank"
-                       title={channel.title}
-                       variant="outline-twitch"
-               >
-                       <Icon.STREAM />
-                       {' '}
-                       {channel.short_name || channel.title}
-               </Button>
-               {onEditRestream && mayEditRestream(user, episode, channel) ?
-                       <Button
-                               className="ms-1"
-                               onClick={() => onEditRestream(episode, channel)}
-                               variant="outline-secondary"
-                       >
-                               <Icon.SETTINGS />
-                       </Button>
-               : null}
-       </div>;
-};
-
-Channel.propTypes = {
-       channel: PropTypes.shape({
-               short_name: PropTypes.string,
-               stream_link: PropTypes.string,
-               title: PropTypes.string,
-       }),
-       episode: PropTypes.shape({
-       }),
-       onEditRestream: PropTypes.func,
-};
-
-export default Channel;
diff --git a/resources/js/components/episodes/Channel.jsx b/resources/js/components/episodes/Channel.jsx
new file mode 100644 (file)
index 0000000..24569be
--- /dev/null
@@ -0,0 +1,38 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+
+import Link from '../channel/Link';
+import Icon from '../common/Icon';
+import { mayEditRestream } from '../../helpers/permissions';
+import { useUser } from '../../hooks/user';
+
+const Channel = ({ channel, episode, onEditRestream }) => {
+       const { user } = useUser();
+
+       return <div className="episode-channel text-nowrap">
+               <Link channel={channel} />
+               {onEditRestream && mayEditRestream(user, episode, channel) ?
+                       <Button
+                               className="ms-1"
+                               onClick={() => onEditRestream(episode, channel)}
+                               variant="outline-secondary"
+                       >
+                               <Icon.SETTINGS />
+                       </Button>
+               : null}
+       </div>;
+};
+
+Channel.propTypes = {
+       channel: PropTypes.shape({
+               short_name: PropTypes.string,
+               stream_link: PropTypes.string,
+               title: PropTypes.string,
+       }),
+       episode: PropTypes.shape({
+       }),
+       onEditRestream: PropTypes.func,
+};
+
+export default Channel;
diff --git a/resources/js/components/episodes/Channels.js b/resources/js/components/episodes/Channels.js
deleted file mode 100644 (file)
index f3fbf05..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Channel from './Channel';
-
-const Channels = ({ channels, episode, onEditRestream }) =>
-       channels.map(channel =>
-               <Channel
-                       channel={channel}
-                       episode={episode}
-                       key={channel.id}
-                       onEditRestream={onEditRestream}
-               />
-       );
-
-Channels.propTypes = {
-       channels: PropTypes.arrayOf(PropTypes.shape({
-       })),
-       episode: PropTypes.shape({
-       }),
-       onEditRestream: PropTypes.func,
-};
-
-export default Channels;
diff --git a/resources/js/components/episodes/Channels.jsx b/resources/js/components/episodes/Channels.jsx
new file mode 100644 (file)
index 0000000..f3fbf05
--- /dev/null
@@ -0,0 +1,24 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Channel from './Channel';
+
+const Channels = ({ channels, episode, onEditRestream }) =>
+       channels.map(channel =>
+               <Channel
+                       channel={channel}
+                       episode={episode}
+                       key={channel.id}
+                       onEditRestream={onEditRestream}
+               />
+       );
+
+Channels.propTypes = {
+       channels: PropTypes.arrayOf(PropTypes.shape({
+       })),
+       episode: PropTypes.shape({
+       }),
+       onEditRestream: PropTypes.func,
+};
+
+export default Channels;
diff --git a/resources/js/components/episodes/Crew.js b/resources/js/components/episodes/Crew.js
deleted file mode 100644 (file)
index d069841..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import CrewMember from './CrewMember';
-import Icon from '../common/Icon';
-import { compareCrew } from '../../helpers/Crew';
-import {
-       getSGLanguages,
-       getSGSignupLink,
-       hasPassed,
-       hasSGRestream,
-} from '../../helpers/Episode';
-import { canApplyForEpisode } from '../../helpers/permissions';
-import { useUser } from '../../hooks/user';
-
-const Crew = ({ episode, onApply }) => {
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       const commentators = React.useMemo(() =>
-               episode.crew.filter(c => c.role === 'commentary').sort(compareCrew)
-       , [episode]);
-       const trackers = React.useMemo(() =>
-               episode.crew.filter(c => c.role === 'tracking').sort(compareCrew)
-       , [episode]);
-       const techies = React.useMemo(() =>
-               episode.crew.filter(c => c.role === 'setup').sort(compareCrew)
-       , [episode]);
-
-       const sgLanguages = React.useMemo(() =>
-               getSGLanguages(episode)
-       , [episode]);
-
-       const showCommentators = React.useMemo(() =>
-               commentators.length || (!hasPassed(episode) && (
-                       canApplyForEpisode(user, episode, 'commentary') ||
-                       hasSGRestream(episode)
-               ))
-       , [commentators, episode, user]);
-
-       const showTracker = React.useMemo(() =>
-               trackers.length || (!hasPassed(episode) && (
-                       canApplyForEpisode(user, episode, 'tracking') ||
-                       hasSGRestream(episode)
-               ))
-       , [episode, trackers, user]);
-
-       return <Row className="episode-crew">
-               {showCommentators ?
-                       <Col xs={6} md>
-                               <div className="fs-6 fs-md-5">
-                                       <Icon.MICROPHONE className="ms-3 me-2" title="" />
-                                       {t('episodes.commentary')}
-                               </div>
-                               {commentators.map(c =>
-                                       <CrewMember crew={c} key={c.id} />
-                               )}
-                               {onApply && canApplyForEpisode(user, episode, 'commentary') ?
-                                       <div className="button-bar m-2">
-                                               <Button
-                                                       onClick={() => onApply(episode, 'commentary')}
-                                                       variant="outline-secondary"
-                                               >
-                                                       {t('button.signUp')}
-                                               </Button>
-                                       </div>
-                               : null}
-                               {hasSGRestream(episode) ?
-                                       <div className="button-bar m-2">
-                                               {sgLanguages.map(lang =>
-                                                       <Button
-                                                               href={getSGSignupLink(episode, lang, 'commentator')}
-                                                               key={lang}
-                                                               target="_blank"
-                                                               variant="outline-secondary"
-                                                       >
-                                                               {`${t('episodes.sgSignUp')} ${lang.toUpperCase()}`}
-                                                       </Button>
-                                               )}
-                                       </div>
-                               : null}
-                       </Col>
-               : null}
-               {showTracker ?
-                       <Col xs={6} md>
-                               <div className="fs-6 fs-md-5">
-                                       <Icon.MOUSE className="ms-3 me-2" title="" />
-                                       {t('episodes.tracking')}
-                               </div>
-                               {trackers.map(c =>
-                                       <CrewMember crew={c} key={c.id} />
-                               )}
-                               {onApply && canApplyForEpisode(user, episode, 'tracking') ?
-                                       <div className="button-bar m-2">
-                                               <Button
-                                                       onClick={() => onApply(episode, 'tracking')}
-                                                       variant="outline-secondary"
-                                               >
-                                                       {t('button.signUp')}
-                                               </Button>
-                                       </div>
-                               : null}
-                               {hasSGRestream(episode) ?
-                                       <div className="button-bar m-2">
-                                               {sgLanguages.map(lang =>
-                                                       <Button
-                                                               href={getSGSignupLink(episode, lang, 'tracker')}
-                                                               key={lang}
-                                                               target="_blank"
-                                                               variant="outline-secondary"
-                                                       >
-                                                               {`${t('episodes.sgSignUp')} ${lang.toUpperCase()}`}
-                                                       </Button>
-                                               )}
-                                       </div>
-                               : null}
-                       </Col>
-               : null}
-               {techies.length ?
-                       <Col xs={6} md>
-                               <div className="fs-6 fs-md-5">
-                                       <Icon.MONITOR className="ms-3 me-2" title="" />
-                                       {t('episodes.setup')}
-                               </div>
-                               {techies.map(c =>
-                                       <CrewMember crew={c} key={c.id} />
-                               )}
-                       </Col>
-               : null}
-       </Row>;
-};
-
-Crew.propTypes = {
-       episode: PropTypes.shape({
-               channels: PropTypes.arrayOf(PropTypes.shape({
-                       id: PropTypes.number,
-               })),
-               crew: PropTypes.arrayOf(PropTypes.shape({
-               })),
-       }),
-       onApply: PropTypes.func,
-};
-
-export default Crew;
diff --git a/resources/js/components/episodes/Crew.jsx b/resources/js/components/episodes/Crew.jsx
new file mode 100644 (file)
index 0000000..d069841
--- /dev/null
@@ -0,0 +1,146 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import CrewMember from './CrewMember';
+import Icon from '../common/Icon';
+import { compareCrew } from '../../helpers/Crew';
+import {
+       getSGLanguages,
+       getSGSignupLink,
+       hasPassed,
+       hasSGRestream,
+} from '../../helpers/Episode';
+import { canApplyForEpisode } from '../../helpers/permissions';
+import { useUser } from '../../hooks/user';
+
+const Crew = ({ episode, onApply }) => {
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       const commentators = React.useMemo(() =>
+               episode.crew.filter(c => c.role === 'commentary').sort(compareCrew)
+       , [episode]);
+       const trackers = React.useMemo(() =>
+               episode.crew.filter(c => c.role === 'tracking').sort(compareCrew)
+       , [episode]);
+       const techies = React.useMemo(() =>
+               episode.crew.filter(c => c.role === 'setup').sort(compareCrew)
+       , [episode]);
+
+       const sgLanguages = React.useMemo(() =>
+               getSGLanguages(episode)
+       , [episode]);
+
+       const showCommentators = React.useMemo(() =>
+               commentators.length || (!hasPassed(episode) && (
+                       canApplyForEpisode(user, episode, 'commentary') ||
+                       hasSGRestream(episode)
+               ))
+       , [commentators, episode, user]);
+
+       const showTracker = React.useMemo(() =>
+               trackers.length || (!hasPassed(episode) && (
+                       canApplyForEpisode(user, episode, 'tracking') ||
+                       hasSGRestream(episode)
+               ))
+       , [episode, trackers, user]);
+
+       return <Row className="episode-crew">
+               {showCommentators ?
+                       <Col xs={6} md>
+                               <div className="fs-6 fs-md-5">
+                                       <Icon.MICROPHONE className="ms-3 me-2" title="" />
+                                       {t('episodes.commentary')}
+                               </div>
+                               {commentators.map(c =>
+                                       <CrewMember crew={c} key={c.id} />
+                               )}
+                               {onApply && canApplyForEpisode(user, episode, 'commentary') ?
+                                       <div className="button-bar m-2">
+                                               <Button
+                                                       onClick={() => onApply(episode, 'commentary')}
+                                                       variant="outline-secondary"
+                                               >
+                                                       {t('button.signUp')}
+                                               </Button>
+                                       </div>
+                               : null}
+                               {hasSGRestream(episode) ?
+                                       <div className="button-bar m-2">
+                                               {sgLanguages.map(lang =>
+                                                       <Button
+                                                               href={getSGSignupLink(episode, lang, 'commentator')}
+                                                               key={lang}
+                                                               target="_blank"
+                                                               variant="outline-secondary"
+                                                       >
+                                                               {`${t('episodes.sgSignUp')} ${lang.toUpperCase()}`}
+                                                       </Button>
+                                               )}
+                                       </div>
+                               : null}
+                       </Col>
+               : null}
+               {showTracker ?
+                       <Col xs={6} md>
+                               <div className="fs-6 fs-md-5">
+                                       <Icon.MOUSE className="ms-3 me-2" title="" />
+                                       {t('episodes.tracking')}
+                               </div>
+                               {trackers.map(c =>
+                                       <CrewMember crew={c} key={c.id} />
+                               )}
+                               {onApply && canApplyForEpisode(user, episode, 'tracking') ?
+                                       <div className="button-bar m-2">
+                                               <Button
+                                                       onClick={() => onApply(episode, 'tracking')}
+                                                       variant="outline-secondary"
+                                               >
+                                                       {t('button.signUp')}
+                                               </Button>
+                                       </div>
+                               : null}
+                               {hasSGRestream(episode) ?
+                                       <div className="button-bar m-2">
+                                               {sgLanguages.map(lang =>
+                                                       <Button
+                                                               href={getSGSignupLink(episode, lang, 'tracker')}
+                                                               key={lang}
+                                                               target="_blank"
+                                                               variant="outline-secondary"
+                                                       >
+                                                               {`${t('episodes.sgSignUp')} ${lang.toUpperCase()}`}
+                                                       </Button>
+                                               )}
+                                       </div>
+                               : null}
+                       </Col>
+               : null}
+               {techies.length ?
+                       <Col xs={6} md>
+                               <div className="fs-6 fs-md-5">
+                                       <Icon.MONITOR className="ms-3 me-2" title="" />
+                                       {t('episodes.setup')}
+                               </div>
+                               {techies.map(c =>
+                                       <CrewMember crew={c} key={c.id} />
+                               )}
+                       </Col>
+               : null}
+       </Row>;
+};
+
+Crew.propTypes = {
+       episode: PropTypes.shape({
+               channels: PropTypes.arrayOf(PropTypes.shape({
+                       id: PropTypes.number,
+               })),
+               crew: PropTypes.arrayOf(PropTypes.shape({
+               })),
+       }),
+       onApply: PropTypes.func,
+};
+
+export default Crew;
diff --git a/resources/js/components/episodes/CrewManagement.js b/resources/js/components/episodes/CrewManagement.js
deleted file mode 100644 (file)
index 7c5d48e..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Form } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import CrewMember from './CrewMember';
-import Icon from '../common/Icon';
-import UserSelect from '../common/UserSelect';
-
-const CrewManagement = ({
-       channel,
-       episode,
-       manageCrew,
-       role,
-}) => {
-       const { t } = useTranslation();
-
-       const crews = React.useMemo(() =>
-               (episode.crew || [])
-               .filter(c => c.channel_id === channel.id && c.role === role)
-       , [channel, episode, role]);
-
-       const addCrew = React.useCallback(user_id => {
-               manageCrew({
-                       add: user_id,
-                       channel_id: channel.id,
-                       episode_id: episode.id,
-                       role,
-               });
-       }, [channel, episode, manageCrew, role]);
-
-       const confirmCrew = React.useCallback(crew => {
-               manageCrew({
-                       channel_id: channel.id,
-                       confirm: crew.id,
-                       episode_id: episode.id,
-                       role,
-               });
-       }, [channel, episode, manageCrew, role]);
-
-       const removeCrew = React.useCallback(crew => {
-               manageCrew({
-                       channel_id: channel.id,
-                       episode_id: episode.id,
-                       remove: crew.id,
-                       role,
-               });
-       }, [channel, episode, manageCrew, role]);
-
-       const unconfirmCrew = React.useCallback(crew => {
-               manageCrew({
-                       channel_id: channel.id,
-                       episode_id: episode.id,
-                       role,
-                       unconfirm: crew.id,
-               });
-       }, [channel, episode, manageCrew, role]);
-
-       return <div className="mt-2">
-               <div className="fs-4">{t(`crew.roles.${role}`)}</div>
-               {crews.map(crew =>
-                       <div className="d-flex align-items-center justify-content-between" key={crew.id}>
-                               <CrewMember crew={crew} />
-                               <div className="button-bar">
-                                       {crew.confirmed ?
-                                               <Button
-                                                       onClick={() => unconfirmCrew(crew)}
-                                                       title={t('button.unconfirm')}
-                                                       variant="outline-danger"
-                                               >
-                                                       <Icon.REJECT title="" />
-                                               </Button>
-                                       : null}
-                                       {!crew.confirmed ?
-                                               <Button
-                                                       onClick={() => confirmCrew(crew)}
-                                                       title={t('button.confirm')}
-                                                       variant="outline-success"
-                                               >
-                                                       <Icon.ACCEPT />
-                                               </Button>
-                                       : null}
-                                       <Button
-                                               onClick={() => removeCrew(crew)}
-                                               title={t('button.remove')}
-                                               variant="outline-danger"
-                                       >
-                                               <Icon.DELETE title="" />
-                                       </Button>
-                               </div>
-                       </div>
-               )}
-               <Form.Group controlId="crew.addUser">
-                       <Form.Label>{t('episodes.restreamDialog.addUser')}</Form.Label>
-                       <Form.Control
-                               as={UserSelect}
-                               onChange={e => addCrew(e.target.value)}
-                               value=""
-                       />
-               </Form.Group>
-       </div>;
-};
-
-CrewManagement.propTypes = {
-       channel: PropTypes.shape({
-               id: PropTypes.number,
-       }),
-       episode: PropTypes.shape({
-               crew: PropTypes.arrayOf(PropTypes.shape({
-                       channel_id: PropTypes.number,
-                       role: PropTypes.string,
-               })),
-               id: PropTypes.number,
-       }),
-       manageCrew: PropTypes.func,
-       role: PropTypes.string,
-};
-
-export default CrewManagement;
diff --git a/resources/js/components/episodes/CrewManagement.jsx b/resources/js/components/episodes/CrewManagement.jsx
new file mode 100644 (file)
index 0000000..7c5d48e
--- /dev/null
@@ -0,0 +1,119 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Form } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import CrewMember from './CrewMember';
+import Icon from '../common/Icon';
+import UserSelect from '../common/UserSelect';
+
+const CrewManagement = ({
+       channel,
+       episode,
+       manageCrew,
+       role,
+}) => {
+       const { t } = useTranslation();
+
+       const crews = React.useMemo(() =>
+               (episode.crew || [])
+               .filter(c => c.channel_id === channel.id && c.role === role)
+       , [channel, episode, role]);
+
+       const addCrew = React.useCallback(user_id => {
+               manageCrew({
+                       add: user_id,
+                       channel_id: channel.id,
+                       episode_id: episode.id,
+                       role,
+               });
+       }, [channel, episode, manageCrew, role]);
+
+       const confirmCrew = React.useCallback(crew => {
+               manageCrew({
+                       channel_id: channel.id,
+                       confirm: crew.id,
+                       episode_id: episode.id,
+                       role,
+               });
+       }, [channel, episode, manageCrew, role]);
+
+       const removeCrew = React.useCallback(crew => {
+               manageCrew({
+                       channel_id: channel.id,
+                       episode_id: episode.id,
+                       remove: crew.id,
+                       role,
+               });
+       }, [channel, episode, manageCrew, role]);
+
+       const unconfirmCrew = React.useCallback(crew => {
+               manageCrew({
+                       channel_id: channel.id,
+                       episode_id: episode.id,
+                       role,
+                       unconfirm: crew.id,
+               });
+       }, [channel, episode, manageCrew, role]);
+
+       return <div className="mt-2">
+               <div className="fs-4">{t(`crew.roles.${role}`)}</div>
+               {crews.map(crew =>
+                       <div className="d-flex align-items-center justify-content-between" key={crew.id}>
+                               <CrewMember crew={crew} />
+                               <div className="button-bar">
+                                       {crew.confirmed ?
+                                               <Button
+                                                       onClick={() => unconfirmCrew(crew)}
+                                                       title={t('button.unconfirm')}
+                                                       variant="outline-danger"
+                                               >
+                                                       <Icon.REJECT title="" />
+                                               </Button>
+                                       : null}
+                                       {!crew.confirmed ?
+                                               <Button
+                                                       onClick={() => confirmCrew(crew)}
+                                                       title={t('button.confirm')}
+                                                       variant="outline-success"
+                                               >
+                                                       <Icon.ACCEPT />
+                                               </Button>
+                                       : null}
+                                       <Button
+                                               onClick={() => removeCrew(crew)}
+                                               title={t('button.remove')}
+                                               variant="outline-danger"
+                                       >
+                                               <Icon.DELETE title="" />
+                                       </Button>
+                               </div>
+                       </div>
+               )}
+               <Form.Group controlId="crew.addUser">
+                       <Form.Label>{t('episodes.restreamDialog.addUser')}</Form.Label>
+                       <Form.Control
+                               as={UserSelect}
+                               onChange={e => addCrew(e.target.value)}
+                               value=""
+                       />
+               </Form.Group>
+       </div>;
+};
+
+CrewManagement.propTypes = {
+       channel: PropTypes.shape({
+               id: PropTypes.number,
+       }),
+       episode: PropTypes.shape({
+               crew: PropTypes.arrayOf(PropTypes.shape({
+                       channel_id: PropTypes.number,
+                       role: PropTypes.string,
+               })),
+               id: PropTypes.number,
+       }),
+       manageCrew: PropTypes.func,
+       role: PropTypes.string,
+};
+
+export default CrewManagement;
diff --git a/resources/js/components/episodes/CrewMember.js b/resources/js/components/episodes/CrewMember.js
deleted file mode 100644 (file)
index 96eb1b1..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-
-import { getName, getStreamLink } from '../../helpers/Crew';
-import { getAvatarUrl } from '../../helpers/User';
-
-const CrewMember = ({ crew }) => {
-       const classNames = [
-               'crew-member',
-               'text-light',
-       ];
-       if (!crew.confirmed) {
-               classNames.push('unconfirmed');
-       }
-       return <Button
-               className={classNames.join(' ')}
-               href={getStreamLink(crew) || null}
-               key={crew.id}
-               rel="noreferer"
-               variant="outline-twitch"
-       >
-               <img alt="" src={getAvatarUrl(crew.user)} />
-               <span>{getName(crew)}</span>
-       </Button>;
-};
-
-CrewMember.propTypes = {
-       crew: PropTypes.shape({
-               confirmed: PropTypes.bool,
-               id: PropTypes.number,
-               user: PropTypes.shape({
-               }),
-       }),
-};
-
-export default CrewMember;
diff --git a/resources/js/components/episodes/CrewMember.jsx b/resources/js/components/episodes/CrewMember.jsx
new file mode 100644 (file)
index 0000000..96eb1b1
--- /dev/null
@@ -0,0 +1,37 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+
+import { getName, getStreamLink } from '../../helpers/Crew';
+import { getAvatarUrl } from '../../helpers/User';
+
+const CrewMember = ({ crew }) => {
+       const classNames = [
+               'crew-member',
+               'text-light',
+       ];
+       if (!crew.confirmed) {
+               classNames.push('unconfirmed');
+       }
+       return <Button
+               className={classNames.join(' ')}
+               href={getStreamLink(crew) || null}
+               key={crew.id}
+               rel="noreferer"
+               variant="outline-twitch"
+       >
+               <img alt="" src={getAvatarUrl(crew.user)} />
+               <span>{getName(crew)}</span>
+       </Button>;
+};
+
+CrewMember.propTypes = {
+       crew: PropTypes.shape({
+               confirmed: PropTypes.bool,
+               id: PropTypes.number,
+               user: PropTypes.shape({
+               }),
+       }),
+};
+
+export default CrewMember;
diff --git a/resources/js/components/episodes/DialogEpisode.js b/resources/js/components/episodes/DialogEpisode.js
deleted file mode 100644 (file)
index c60b052..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-import { getName } from '../../helpers/Crew';
-
-const DialogEpisode = ({ episode }) => {
-       const { t } = useTranslation();
-
-       if (!episode) return null;
-
-       return <>
-               <div>
-                       {episode.event.title}
-               </div>
-               <div>
-                       {t('episodes.startTime', { date: new Date(episode.start) })}
-               </div>
-               <div>
-                       {episode.players.map(p => getName(p)).join(', ')}
-               </div>
-       </>;
-};
-
-DialogEpisode.propTypes = {
-       episode: PropTypes.shape({
-               event: PropTypes.shape({
-                       title: PropTypes.string,
-               }),
-               players: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               start: PropTypes.string,
-       }),
-};
-
-export default DialogEpisode;
diff --git a/resources/js/components/episodes/DialogEpisode.jsx b/resources/js/components/episodes/DialogEpisode.jsx
new file mode 100644 (file)
index 0000000..c60b052
--- /dev/null
@@ -0,0 +1,36 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import { getName } from '../../helpers/Crew';
+
+const DialogEpisode = ({ episode }) => {
+       const { t } = useTranslation();
+
+       if (!episode) return null;
+
+       return <>
+               <div>
+                       {episode.event.title}
+               </div>
+               <div>
+                       {t('episodes.startTime', { date: new Date(episode.start) })}
+               </div>
+               <div>
+                       {episode.players.map(p => getName(p)).join(', ')}
+               </div>
+       </>;
+};
+
+DialogEpisode.propTypes = {
+       episode: PropTypes.shape({
+               event: PropTypes.shape({
+                       title: PropTypes.string,
+               }),
+               players: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               start: PropTypes.string,
+       }),
+};
+
+export default DialogEpisode;
diff --git a/resources/js/components/episodes/Filter.js b/resources/js/components/episodes/Filter.js
deleted file mode 100644 (file)
index 98d965d..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-
-import { isEventSelected, toggleEventFilter } from '../../helpers/Episode';
-
-const Filter = ({ events, filter, setFilter }) => {
-       const toggleEvent = React.useCallback(event => {
-               setFilter(toggleEventFilter(events, filter, event));
-       }, [events, filter, setFilter]);
-
-       if (!events || !events.length) return null;
-
-       return <div className="episode-filter button-bar text-end">
-               {events.map(event =>
-                       <Button
-                               active={isEventSelected(filter, event)}
-                               key={event.id}
-                               onClick={() => toggleEvent(event)}
-                               title={event.short ? event.title : null}
-                               variant="outline-secondary"
-                       >
-                               {event.short || event.title}
-                       </Button>
-               )}
-       </div>;
-};
-
-Filter.propTypes = {
-       events: PropTypes.arrayOf(PropTypes.shape({
-       })),
-       filter: PropTypes.shape(),
-       setFilter: PropTypes.func,
-};
-
-export default Filter;
diff --git a/resources/js/components/episodes/Filter.jsx b/resources/js/components/episodes/Filter.jsx
new file mode 100644 (file)
index 0000000..98d965d
--- /dev/null
@@ -0,0 +1,36 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+
+import { isEventSelected, toggleEventFilter } from '../../helpers/Episode';
+
+const Filter = ({ events, filter, setFilter }) => {
+       const toggleEvent = React.useCallback(event => {
+               setFilter(toggleEventFilter(events, filter, event));
+       }, [events, filter, setFilter]);
+
+       if (!events || !events.length) return null;
+
+       return <div className="episode-filter button-bar text-end">
+               {events.map(event =>
+                       <Button
+                               active={isEventSelected(filter, event)}
+                               key={event.id}
+                               onClick={() => toggleEvent(event)}
+                               title={event.short ? event.title : null}
+                               variant="outline-secondary"
+                       >
+                               {event.short || event.title}
+                       </Button>
+               )}
+       </div>;
+};
+
+Filter.propTypes = {
+       events: PropTypes.arrayOf(PropTypes.shape({
+       })),
+       filter: PropTypes.shape(),
+       setFilter: PropTypes.func,
+};
+
+export default Filter;
diff --git a/resources/js/components/episodes/Item.js b/resources/js/components/episodes/Item.js
deleted file mode 100644 (file)
index 612c5ea..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-import { Link } from 'react-router-dom';
-
-import Channels from './Channels';
-import Crew from './Crew';
-import MultiLink from './MultiLink';
-import Players from './Players';
-import Icon from '../common/Icon';
-import { hasPassed, hasSGRestream, isActive } from '../../helpers/Episode';
-import { getLink } from '../../helpers/Event';
-import { canApplyForEpisode, canRestreamEpisode } from '../../helpers/permissions';
-import { useUser } from '../../hooks/user';
-
-const Item = ({ episode, onAddRestream, onApply, onEditRestream }) => {
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       const classNames = [
-               'episodes-item',
-               'my-3',
-               'p-2',
-               'border',
-               'rounded',
-       ];
-       if (isActive(episode)) {
-               classNames.push('is-active');
-       }
-
-       const style = React.useMemo(() => {
-               if (episode.event && episode.event.corner) {
-                       return {
-                               backgroundImage: `url(${episode.event.corner})`,
-                       };
-               }
-               return null;
-       }, [episode.event && episode.event.corner]);
-
-       const hasChannels = episode.channels && episode.channels.length;
-       const hasPlayers = episode.players && episode.players.length;
-
-       return <div className={classNames.join(' ')} style={style}>
-               <div className="d-flex align-items-stretch">
-                       <div className="episode-start me-3 fs-5 fs-md-4 text-end">
-                               {t('schedule.startTime', { date: new Date(episode.start) })}
-                       </div>
-                       <div className="episode-titlebar">
-                               {episode.title || episode.event ?
-                                       <div className="episode-title fs-5 fs-md-4">
-                                               {episode.title || episode.event.title}
-                                       </div>
-                               : null}
-                               {episode.comment ?
-                                       <div className="episode-comment">
-                                               {episode.comment}
-                                       </div>
-                               : null}
-                       </div>
-                       <div className="episode-channel-links ms-auto text-end">
-                               {hasChannels ?
-                                       <Channels
-                                               channels={episode.channels}
-                                               episode={episode}
-                                               onEditRestream={onEditRestream}
-                                       />
-                               : null}
-                               {!hasChannels && hasPlayers ?
-                                       <MultiLink players={episode.players} />
-                               : null}
-                               {episode.raceroom ?
-                                       <div>
-                                               <Button
-                                                       href={episode.raceroom}
-                                                       target="_blank"
-                                                       title={t('episodes.raceroom')}
-                                                       variant="outline-secondary"
-                                               >
-                                                       <Icon.RACETIME title="" />
-                                                       {' '}
-                                                       {t('episodes.raceroom')}
-                                               </Button>
-                                       </div>
-                               : null}
-                               {onAddRestream && canRestreamEpisode(user, episode) ?
-                                       <div>
-                                               <Button
-                                                       onClick={() => onAddRestream(episode)}
-                                                       title={t('episodes.addRestream')}
-                                                       variant="outline-secondary"
-                                               >
-                                                       <Icon.ADD title="" />
-                                               </Button>
-                                       </div>
-                               : null}
-                       </div>
-               </div>
-               <div className="episode-body d-flex flex-column flex-fill">
-                       {hasPlayers ?
-                               <Players players={episode.players} />
-                       : null}
-                       {(episode.crew && episode.crew.length) || (!hasPassed(episode) && (
-                                       hasSGRestream(episode)
-                                       || canApplyForEpisode(user, episode, 'commentary')
-                                       || canApplyForEpisode(user, episode, 'tracking')
-                       )) ?
-                               <div className="mb-3">
-                                       <Crew episode={episode} onApply={onApply} />
-                               </div>
-                       : null}
-                       {episode.event ?
-                               <div className="episode-event mt-auto">
-                                       {episode.event.description_id ?
-                                               <Link className="event-link" to={getLink(episode.event)}>
-                                                       {episode.event.title}
-                                               </Link>
-                                       :
-                                               episode.event.title
-                                       }
-                               </div>
-                       : null}
-               </div>
-       </div>;
-};
-
-Item.propTypes = {
-       episode: PropTypes.shape({
-               channels: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               comment: PropTypes.string,
-               crew: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               event: PropTypes.shape({
-                       corner: PropTypes.string,
-                       description_id: PropTypes.number,
-                       name: PropTypes.string,
-                       title: PropTypes.string,
-               }),
-               players: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               raceroom: PropTypes.string,
-               start: PropTypes.string,
-               title: PropTypes.string,
-       }),
-       onAddRestream: PropTypes.func,
-       onApply: PropTypes.func,
-       onEditRestream: PropTypes.func,
-};
-
-export default Item;
diff --git a/resources/js/components/episodes/Item.jsx b/resources/js/components/episodes/Item.jsx
new file mode 100644 (file)
index 0000000..612c5ea
--- /dev/null
@@ -0,0 +1,151 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import { Link } from 'react-router-dom';
+
+import Channels from './Channels';
+import Crew from './Crew';
+import MultiLink from './MultiLink';
+import Players from './Players';
+import Icon from '../common/Icon';
+import { hasPassed, hasSGRestream, isActive } from '../../helpers/Episode';
+import { getLink } from '../../helpers/Event';
+import { canApplyForEpisode, canRestreamEpisode } from '../../helpers/permissions';
+import { useUser } from '../../hooks/user';
+
+const Item = ({ episode, onAddRestream, onApply, onEditRestream }) => {
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       const classNames = [
+               'episodes-item',
+               'my-3',
+               'p-2',
+               'border',
+               'rounded',
+       ];
+       if (isActive(episode)) {
+               classNames.push('is-active');
+       }
+
+       const style = React.useMemo(() => {
+               if (episode.event && episode.event.corner) {
+                       return {
+                               backgroundImage: `url(${episode.event.corner})`,
+                       };
+               }
+               return null;
+       }, [episode.event && episode.event.corner]);
+
+       const hasChannels = episode.channels && episode.channels.length;
+       const hasPlayers = episode.players && episode.players.length;
+
+       return <div className={classNames.join(' ')} style={style}>
+               <div className="d-flex align-items-stretch">
+                       <div className="episode-start me-3 fs-5 fs-md-4 text-end">
+                               {t('schedule.startTime', { date: new Date(episode.start) })}
+                       </div>
+                       <div className="episode-titlebar">
+                               {episode.title || episode.event ?
+                                       <div className="episode-title fs-5 fs-md-4">
+                                               {episode.title || episode.event.title}
+                                       </div>
+                               : null}
+                               {episode.comment ?
+                                       <div className="episode-comment">
+                                               {episode.comment}
+                                       </div>
+                               : null}
+                       </div>
+                       <div className="episode-channel-links ms-auto text-end">
+                               {hasChannels ?
+                                       <Channels
+                                               channels={episode.channels}
+                                               episode={episode}
+                                               onEditRestream={onEditRestream}
+                                       />
+                               : null}
+                               {!hasChannels && hasPlayers ?
+                                       <MultiLink players={episode.players} />
+                               : null}
+                               {episode.raceroom ?
+                                       <div>
+                                               <Button
+                                                       href={episode.raceroom}
+                                                       target="_blank"
+                                                       title={t('episodes.raceroom')}
+                                                       variant="outline-secondary"
+                                               >
+                                                       <Icon.RACETIME title="" />
+                                                       {' '}
+                                                       {t('episodes.raceroom')}
+                                               </Button>
+                                       </div>
+                               : null}
+                               {onAddRestream && canRestreamEpisode(user, episode) ?
+                                       <div>
+                                               <Button
+                                                       onClick={() => onAddRestream(episode)}
+                                                       title={t('episodes.addRestream')}
+                                                       variant="outline-secondary"
+                                               >
+                                                       <Icon.ADD title="" />
+                                               </Button>
+                                       </div>
+                               : null}
+                       </div>
+               </div>
+               <div className="episode-body d-flex flex-column flex-fill">
+                       {hasPlayers ?
+                               <Players players={episode.players} />
+                       : null}
+                       {(episode.crew && episode.crew.length) || (!hasPassed(episode) && (
+                                       hasSGRestream(episode)
+                                       || canApplyForEpisode(user, episode, 'commentary')
+                                       || canApplyForEpisode(user, episode, 'tracking')
+                       )) ?
+                               <div className="mb-3">
+                                       <Crew episode={episode} onApply={onApply} />
+                               </div>
+                       : null}
+                       {episode.event ?
+                               <div className="episode-event mt-auto">
+                                       {episode.event.description_id ?
+                                               <Link className="event-link" to={getLink(episode.event)}>
+                                                       {episode.event.title}
+                                               </Link>
+                                       :
+                                               episode.event.title
+                                       }
+                               </div>
+                       : null}
+               </div>
+       </div>;
+};
+
+Item.propTypes = {
+       episode: PropTypes.shape({
+               channels: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               comment: PropTypes.string,
+               crew: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               event: PropTypes.shape({
+                       corner: PropTypes.string,
+                       description_id: PropTypes.number,
+                       name: PropTypes.string,
+                       title: PropTypes.string,
+               }),
+               players: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               raceroom: PropTypes.string,
+               start: PropTypes.string,
+               title: PropTypes.string,
+       }),
+       onAddRestream: PropTypes.func,
+       onApply: PropTypes.func,
+       onEditRestream: PropTypes.func,
+};
+
+export default Item;
diff --git a/resources/js/components/episodes/List.js b/resources/js/components/episodes/List.js
deleted file mode 100644 (file)
index a2a3b29..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-import moment from 'moment';
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Item from './Item';
-
-const List = ({ episodes, onAddRestream, onApply, onEditRestream }) => {
-       const grouped = React.useMemo(() => episodes.reduce((groups, episode) => {
-               const day = moment(episode.start).format('YYYY-MM-DD');
-               return {
-                       ...groups,
-                       [day]: [
-                               ...groups[day] || [],
-                               episode,
-                       ],
-               };
-       }, {}), [episodes]);
-
-       return <div className="episodes-list">
-               {Object.entries(grouped).map(([day, group]) => <div key={day}>
-                       <h2 className="text-center episodes-group-heading">
-                               {moment(day).format('dddd, L')}
-                       </h2>
-                       {group.map(episode =>
-                               <Item
-                                       episode={episode}
-                                       onAddRestream={onAddRestream}
-                                       onApply={onApply}
-                                       onEditRestream={onEditRestream}
-                                       key={episode.id}
-                               />
-                       )}
-               </div>)}
-       </div>;
-};
-
-List.propTypes = {
-       episodes: PropTypes.arrayOf(PropTypes.shape({
-               start: PropTypes.string,
-       })),
-       onAddRestream: PropTypes.func,
-       onApply: PropTypes.func,
-       onEditRestream: PropTypes.func,
-};
-
-export default List;
diff --git a/resources/js/components/episodes/List.jsx b/resources/js/components/episodes/List.jsx
new file mode 100644 (file)
index 0000000..fc562ea
--- /dev/null
@@ -0,0 +1,67 @@
+import moment from 'moment';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Item from './Item';
+
+const List = ({
+       compact = false,
+       episodes,
+       onAddRestream,
+       onApply,
+       onEditRestream,
+}) => {
+       const grouped = React.useMemo(() => episodes.reduce((groups, episode) => {
+               const day = moment(episode.start).format('YYYY-MM-DD');
+               return {
+                       ...groups,
+                       [day]: [
+                               ...groups[day] || [],
+                               episode,
+                       ],
+               };
+       }, {}), [episodes]);
+
+       const className = React.useMemo(() => {
+               const classNames = ['episodes-list'];
+               if (compact) {
+                       classNames.push('compact');
+               }
+               return classNames.join(' ');
+       }, [compact]);
+
+       return <div className={className}>
+               {Object.entries(grouped).map(([day, group]) => <div key={day}>
+                       {compact ?
+                               <h3 className="episodes-group-heading">
+                                       {moment(day).format('dddd, L')}
+                               </h3>
+                       :
+                               <h2 className="text-center episodes-group-heading">
+                                       {moment(day).format('dddd, L')}
+                               </h2>
+                       }
+                       {group.map(episode =>
+                               <Item
+                                       episode={episode}
+                                       onAddRestream={onAddRestream}
+                                       onApply={onApply}
+                                       onEditRestream={onEditRestream}
+                                       key={episode.id}
+                               />
+                       )}
+               </div>)}
+       </div>;
+};
+
+List.propTypes = {
+       compact: PropTypes.bool,
+       episodes: PropTypes.arrayOf(PropTypes.shape({
+               start: PropTypes.string,
+       })),
+       onAddRestream: PropTypes.func,
+       onApply: PropTypes.func,
+       onEditRestream: PropTypes.func,
+};
+
+export default List;
diff --git a/resources/js/components/episodes/MultiLink.js b/resources/js/components/episodes/MultiLink.js
deleted file mode 100644 (file)
index 2f737dd..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-
-import Icon from '../common/Icon';
-import { getStreamLink } from '../../helpers/Crew';
-
-const MultiLink = ({ players }) => {
-       const streams = players.map(getStreamLink);
-       const names = streams.map(s => s.split('/').pop());
-       const url = `https://multistre.am/${names.join('/')}`;
-
-       return <div className="episode-channel">
-               <Button
-                       href={url}
-                       rel="noreferer"
-                       target="_blank"
-                       title="MultiTwitch"
-                       variant="outline-twitch"
-               >
-                       <Icon.STREAM />
-                       {' MultiStream'}
-               </Button>
-       </div>;
-};
-
-MultiLink.propTypes = {
-       players: PropTypes.arrayOf(PropTypes.shape({
-               short_name: PropTypes.string,
-               stream_link: PropTypes.string,
-               title: PropTypes.string,
-       })),
-};
-
-export default MultiLink;
diff --git a/resources/js/components/episodes/MultiLink.jsx b/resources/js/components/episodes/MultiLink.jsx
new file mode 100644 (file)
index 0000000..2f737dd
--- /dev/null
@@ -0,0 +1,35 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+
+import Icon from '../common/Icon';
+import { getStreamLink } from '../../helpers/Crew';
+
+const MultiLink = ({ players }) => {
+       const streams = players.map(getStreamLink);
+       const names = streams.map(s => s.split('/').pop());
+       const url = `https://multistre.am/${names.join('/')}`;
+
+       return <div className="episode-channel">
+               <Button
+                       href={url}
+                       rel="noreferer"
+                       target="_blank"
+                       title="MultiTwitch"
+                       variant="outline-twitch"
+               >
+                       <Icon.STREAM />
+                       {' MultiStream'}
+               </Button>
+       </div>;
+};
+
+MultiLink.propTypes = {
+       players: PropTypes.arrayOf(PropTypes.shape({
+               short_name: PropTypes.string,
+               stream_link: PropTypes.string,
+               title: PropTypes.string,
+       })),
+};
+
+export default MultiLink;
diff --git a/resources/js/components/episodes/Player.js b/resources/js/components/episodes/Player.js
deleted file mode 100644 (file)
index 3fc285f..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-
-import { getName, getStreamLink } from '../../helpers/Crew';
-import { getAvatarUrl } from '../../helpers/User';
-
-const Player = ({ player }) => {
-       return <div className="episode-player my-3">
-               <Button
-                       className="player-link"
-                       href={getStreamLink(player)}
-                       rel="noreferrer"
-                       target="_blank"
-                       variant="outline-twitch"
-               >
-                       <img alt="" src={getAvatarUrl(player.user)} />
-                       <span className="text-light fs-5 fs-md-4">{getName(player)}</span>
-               </Button>
-       </div>;
-};
-
-Player.propTypes = {
-       player: PropTypes.shape({
-               id: PropTypes.number,
-               name_override: PropTypes.string,
-               stream_override: PropTypes.string,
-               user: PropTypes.shape({
-               }),
-       }),
-};
-
-export default Player;
diff --git a/resources/js/components/episodes/Player.jsx b/resources/js/components/episodes/Player.jsx
new file mode 100644 (file)
index 0000000..3fc285f
--- /dev/null
@@ -0,0 +1,33 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+
+import { getName, getStreamLink } from '../../helpers/Crew';
+import { getAvatarUrl } from '../../helpers/User';
+
+const Player = ({ player }) => {
+       return <div className="episode-player my-3">
+               <Button
+                       className="player-link"
+                       href={getStreamLink(player)}
+                       rel="noreferrer"
+                       target="_blank"
+                       variant="outline-twitch"
+               >
+                       <img alt="" src={getAvatarUrl(player.user)} />
+                       <span className="text-light fs-5 fs-md-4">{getName(player)}</span>
+               </Button>
+       </div>;
+};
+
+Player.propTypes = {
+       player: PropTypes.shape({
+               id: PropTypes.number,
+               name_override: PropTypes.string,
+               stream_override: PropTypes.string,
+               user: PropTypes.shape({
+               }),
+       }),
+};
+
+export default Player;
diff --git a/resources/js/components/episodes/Players.js b/resources/js/components/episodes/Players.js
deleted file mode 100644 (file)
index 3a3cf59..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Player from './Player';
-
-const Players = ({ players }) =>
-       <div className="episode-players">
-               {players.map(player =>
-                       <Player key={player.id} player={player} />
-               )}
-       </div>;
-
-Players.propTypes = {
-       players: PropTypes.arrayOf(PropTypes.shape({
-               id: PropTypes.number,
-       })),
-};
-
-export default Players;
diff --git a/resources/js/components/episodes/Players.jsx b/resources/js/components/episodes/Players.jsx
new file mode 100644 (file)
index 0000000..3a3cf59
--- /dev/null
@@ -0,0 +1,19 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Player from './Player';
+
+const Players = ({ players }) =>
+       <div className="episode-players">
+               {players.map(player =>
+                       <Player key={player.id} player={player} />
+               )}
+       </div>;
+
+Players.propTypes = {
+       players: PropTypes.arrayOf(PropTypes.shape({
+               id: PropTypes.number,
+       })),
+};
+
+export default Players;
diff --git a/resources/js/components/episodes/RestreamAddForm.js b/resources/js/components/episodes/RestreamAddForm.js
deleted file mode 100644 (file)
index c09b92b..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import DialogEpisode from './DialogEpisode';
-import ToggleSwitch from '../common/ToggleSwitch';
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import { withUser } from '../../hooks/user';
-
-const channelCompare = (a, b) => a.channel.title.localeCompare(b.channel.title);
-
-const RestreamAddForm = ({
-       episode,
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       touched,
-       user,
-       values,
-}) => {
-       const { t } = useTranslation();
-
-       return <Form noValidate onSubmit={handleSubmit}>
-               <Modal.Body>
-                       <DialogEpisode episode={episode} />
-                       <Form.Group controlId="episodes.channel_id">
-                               <Form.Label>{t('episodes.channel')}</Form.Label>
-                               <Form.Select
-                                       isInvalid={!!(touched.channel_id && errors.channel_id)}
-                                       name="channel_id"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.channel_id || 0}
-                               >
-                                       <option disabled value={0}>{t('general.pleaseSelect')}</option>
-                                       {((user && user.channel_crews) || []).sort(channelCompare).map(c =>
-                                               <option key={c.id} value={c.channel_id}>
-                                                       {c.channel.title}
-                                               </option>
-                                       )}
-                               </Form.Select>
-                               {touched.channel_id && errors.channel_id ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.channel_id)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Row>
-                               <Form.Group as={Col} sm={6} controlId="episodes.accept_comms">
-                                       <Form.Label className="d-block">
-                                               {t('episodes.restreamDialog.acceptComms')}
-                                       </Form.Label>
-                                       <Form.Control
-                                               as={ToggleSwitch}
-                                               isInvalid={!!(touched.accept_comms && errors.accept_comms)}
-                                               name="accept_comms"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               value={!!values.accept_comms}
-                                       />
-                                       {touched.accept_comms && errors.accept_comms ?
-                                               <Form.Control.Feedback type="invalid">
-                                                       {t(errors.accept_comms)}
-                                               </Form.Control.Feedback>
-                                       : null}
-                               </Form.Group>
-                               <Form.Group as={Col} sm={6} controlId="episodes.accept_tracker">
-                                       <Form.Label className="d-block">
-                                               {t('episodes.restreamDialog.acceptTracker')}
-                                       </Form.Label>
-                                       <Form.Control
-                                               as={ToggleSwitch}
-                                               isInvalid={!!(touched.accept_tracker && errors.accept_tracker)}
-                                               name="accept_tracker"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               value={!!values.accept_tracker}
-                                       />
-                                       {touched.accept_tracker && errors.accept_tracker ?
-                                               <Form.Control.Feedback type="invalid">
-                                                       {t(errors.accept_tracker)}
-                                               </Form.Control.Feedback>
-                                       : null}
-                               </Form.Group>
-                       </Row>
-               </Modal.Body>
-               <Modal.Footer>
-                       {onCancel ?
-                               <Button onClick={onCancel} variant="secondary">
-                                       {t('button.cancel')}
-                               </Button>
-                       : null}
-                       <Button type="submit" variant="primary">
-                               {t('button.save')}
-                       </Button>
-               </Modal.Footer>
-       </Form>;
-};
-
-RestreamAddForm.propTypes = {
-       episode: PropTypes.shape({
-               event: PropTypes.shape({
-                       title: PropTypes.string,
-               }),
-               players: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               start: PropTypes.string,
-       }),
-       errors: PropTypes.shape({
-               accept_comms: PropTypes.string,
-               accept_tracker: PropTypes.string,
-               channel_id: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               accept_comms: PropTypes.bool,
-               accept_tracker: PropTypes.bool,
-               channel_id: PropTypes.bool,
-       }),
-       user: PropTypes.shape({
-               channel_crews: PropTypes.arrayOf(PropTypes.shape({
-               })),
-       }),
-       values: PropTypes.shape({
-               accept_comms: PropTypes.bool,
-               accept_tracker: PropTypes.bool,
-               channel_id: PropTypes.number,
-       }),
-};
-
-export default withUser(withFormik({
-       displayName: 'RestreamAddForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { setErrors } = actions;
-               const { onSubmit } = actions.props;
-               try {
-                       await onSubmit(values);
-               } catch (e) {
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ episode, user }) => ({
-               accept_comms: false,
-               accept_tracker: false,
-               channel_id: user && user.channel_crews && user.channel_crews.length
-                       ? user.channel_crews[0].channel_id : 0,
-               episode_id: episode ? episode.id : 0,
-       }),
-})(RestreamAddForm));
diff --git a/resources/js/components/episodes/RestreamAddForm.jsx b/resources/js/components/episodes/RestreamAddForm.jsx
new file mode 100644 (file)
index 0000000..c09b92b
--- /dev/null
@@ -0,0 +1,159 @@
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import DialogEpisode from './DialogEpisode';
+import ToggleSwitch from '../common/ToggleSwitch';
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import { withUser } from '../../hooks/user';
+
+const channelCompare = (a, b) => a.channel.title.localeCompare(b.channel.title);
+
+const RestreamAddForm = ({
+       episode,
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       touched,
+       user,
+       values,
+}) => {
+       const { t } = useTranslation();
+
+       return <Form noValidate onSubmit={handleSubmit}>
+               <Modal.Body>
+                       <DialogEpisode episode={episode} />
+                       <Form.Group controlId="episodes.channel_id">
+                               <Form.Label>{t('episodes.channel')}</Form.Label>
+                               <Form.Select
+                                       isInvalid={!!(touched.channel_id && errors.channel_id)}
+                                       name="channel_id"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.channel_id || 0}
+                               >
+                                       <option disabled value={0}>{t('general.pleaseSelect')}</option>
+                                       {((user && user.channel_crews) || []).sort(channelCompare).map(c =>
+                                               <option key={c.id} value={c.channel_id}>
+                                                       {c.channel.title}
+                                               </option>
+                                       )}
+                               </Form.Select>
+                               {touched.channel_id && errors.channel_id ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.channel_id)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Row>
+                               <Form.Group as={Col} sm={6} controlId="episodes.accept_comms">
+                                       <Form.Label className="d-block">
+                                               {t('episodes.restreamDialog.acceptComms')}
+                                       </Form.Label>
+                                       <Form.Control
+                                               as={ToggleSwitch}
+                                               isInvalid={!!(touched.accept_comms && errors.accept_comms)}
+                                               name="accept_comms"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               value={!!values.accept_comms}
+                                       />
+                                       {touched.accept_comms && errors.accept_comms ?
+                                               <Form.Control.Feedback type="invalid">
+                                                       {t(errors.accept_comms)}
+                                               </Form.Control.Feedback>
+                                       : null}
+                               </Form.Group>
+                               <Form.Group as={Col} sm={6} controlId="episodes.accept_tracker">
+                                       <Form.Label className="d-block">
+                                               {t('episodes.restreamDialog.acceptTracker')}
+                                       </Form.Label>
+                                       <Form.Control
+                                               as={ToggleSwitch}
+                                               isInvalid={!!(touched.accept_tracker && errors.accept_tracker)}
+                                               name="accept_tracker"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               value={!!values.accept_tracker}
+                                       />
+                                       {touched.accept_tracker && errors.accept_tracker ?
+                                               <Form.Control.Feedback type="invalid">
+                                                       {t(errors.accept_tracker)}
+                                               </Form.Control.Feedback>
+                                       : null}
+                               </Form.Group>
+                       </Row>
+               </Modal.Body>
+               <Modal.Footer>
+                       {onCancel ?
+                               <Button onClick={onCancel} variant="secondary">
+                                       {t('button.cancel')}
+                               </Button>
+                       : null}
+                       <Button type="submit" variant="primary">
+                               {t('button.save')}
+                       </Button>
+               </Modal.Footer>
+       </Form>;
+};
+
+RestreamAddForm.propTypes = {
+       episode: PropTypes.shape({
+               event: PropTypes.shape({
+                       title: PropTypes.string,
+               }),
+               players: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               start: PropTypes.string,
+       }),
+       errors: PropTypes.shape({
+               accept_comms: PropTypes.string,
+               accept_tracker: PropTypes.string,
+               channel_id: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               accept_comms: PropTypes.bool,
+               accept_tracker: PropTypes.bool,
+               channel_id: PropTypes.bool,
+       }),
+       user: PropTypes.shape({
+               channel_crews: PropTypes.arrayOf(PropTypes.shape({
+               })),
+       }),
+       values: PropTypes.shape({
+               accept_comms: PropTypes.bool,
+               accept_tracker: PropTypes.bool,
+               channel_id: PropTypes.number,
+       }),
+};
+
+export default withUser(withFormik({
+       displayName: 'RestreamAddForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { setErrors } = actions;
+               const { onSubmit } = actions.props;
+               try {
+                       await onSubmit(values);
+               } catch (e) {
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ episode, user }) => ({
+               accept_comms: false,
+               accept_tracker: false,
+               channel_id: user && user.channel_crews && user.channel_crews.length
+                       ? user.channel_crews[0].channel_id : 0,
+               episode_id: episode ? episode.id : 0,
+       }),
+})(RestreamAddForm));
diff --git a/resources/js/components/episodes/RestreamDialog.js b/resources/js/components/episodes/RestreamDialog.js
deleted file mode 100644 (file)
index 2b7454b..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import RestreamAddForm from './RestreamAddForm';
-import RestreamEditForm from './RestreamEditForm';
-
-const RestreamDialog = ({
-       channel,
-       editRestream,
-       episode,
-       manageCrew,
-       onHide,
-       onRemoveRestream,
-       onSubmit,
-       show,
-}) => {
-       const { t } = useTranslation();
-
-       return <Modal className="restream-dialog" onHide={onHide} show={show}>
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {t('episodes.restreamDialog.title')}
-                       </Modal.Title>
-               </Modal.Header>
-               {channel ?
-                       <RestreamEditForm
-                               channel={channel}
-                               editRestream={editRestream}
-                               episode={episode}
-                               manageCrew={manageCrew}
-                               onCancel={onHide}
-                               onRemoveRestream={onRemoveRestream}
-                       />
-               :
-                       <RestreamAddForm
-                               episode={episode}
-                               onCancel={onHide}
-                               onSubmit={onSubmit}
-                       />
-               }
-       </Modal>;
-};
-
-RestreamDialog.propTypes = {
-       channel: PropTypes.shape({
-       }),
-       editRestream: PropTypes.func,
-       episode: PropTypes.shape({
-       }),
-       manageCrew: PropTypes.func,
-       onHide: PropTypes.func,
-       onRemoveRestream: PropTypes.func,
-       onSubmit: PropTypes.func,
-       show: PropTypes.bool,
-};
-
-export default RestreamDialog;
diff --git a/resources/js/components/episodes/RestreamDialog.jsx b/resources/js/components/episodes/RestreamDialog.jsx
new file mode 100644 (file)
index 0000000..2b7454b
--- /dev/null
@@ -0,0 +1,59 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import RestreamAddForm from './RestreamAddForm';
+import RestreamEditForm from './RestreamEditForm';
+
+const RestreamDialog = ({
+       channel,
+       editRestream,
+       episode,
+       manageCrew,
+       onHide,
+       onRemoveRestream,
+       onSubmit,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal className="restream-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('episodes.restreamDialog.title')}
+                       </Modal.Title>
+               </Modal.Header>
+               {channel ?
+                       <RestreamEditForm
+                               channel={channel}
+                               editRestream={editRestream}
+                               episode={episode}
+                               manageCrew={manageCrew}
+                               onCancel={onHide}
+                               onRemoveRestream={onRemoveRestream}
+                       />
+               :
+                       <RestreamAddForm
+                               episode={episode}
+                               onCancel={onHide}
+                               onSubmit={onSubmit}
+                       />
+               }
+       </Modal>;
+};
+
+RestreamDialog.propTypes = {
+       channel: PropTypes.shape({
+       }),
+       editRestream: PropTypes.func,
+       episode: PropTypes.shape({
+       }),
+       manageCrew: PropTypes.func,
+       onHide: PropTypes.func,
+       onRemoveRestream: PropTypes.func,
+       onSubmit: PropTypes.func,
+       show: PropTypes.bool,
+};
+
+export default RestreamDialog;
diff --git a/resources/js/components/episodes/RestreamEditForm.js b/resources/js/components/episodes/RestreamEditForm.js
deleted file mode 100644 (file)
index 84a3ea2..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import CrewManagement from './CrewManagement';
-import ToggleSwitch from '../common/ToggleSwitch';
-import { getName } from '../../helpers/Crew';
-
-const RestreamEditForm = ({
-       channel,
-       editRestream,
-       episode,
-       manageCrew,
-       onCancel,
-       onRemoveRestream,
-}) => {
-       const { t } = useTranslation();
-
-       const acceptToggle = React.useCallback(e => {
-               editRestream({
-                       channel_id: channel.id,
-                       episode_id: episode.id,
-                       [e.target.name]: e.target.value,
-               });
-       }, [channel, editRestream, episode]);
-
-       return <>
-               <Modal.Body>
-                       {channel ?
-                               <div>
-                                       {channel.title}
-                               </div>
-                       : null}
-                       {episode ? <>
-                               <div>
-                                       {episode.event.title}
-                               </div>
-                               <div>
-                                       {t('episodes.startTime', { date: new Date(episode.start) })}
-                               </div>
-                               <div>
-                                       {episode.players.map(p => getName(p)).join(', ')}
-                               </div>
-                       </> : null}
-                       {channel && episode && editRestream ?
-                               <Row>
-                                       <Form.Group as={Col} sm={6} controlId="episodes.accept_comms">
-                                               <Form.Label className="d-block">
-                                                       {t('episodes.restreamDialog.acceptComms')}
-                                               </Form.Label>
-                                               <Form.Control
-                                                       as={ToggleSwitch}
-                                                       name="accept_comms"
-                                                       onChange={acceptToggle}
-                                                       value={!!channel.pivot.accept_comms}
-                                               />
-                                       </Form.Group>
-                                       <Form.Group as={Col} sm={6} controlId="episodes.accept_tracker">
-                                               <Form.Label className="d-block">
-                                                       {t('episodes.restreamDialog.acceptTracker')}
-                                               </Form.Label>
-                                               <Form.Control
-                                                       as={ToggleSwitch}
-                                                       name="accept_tracker"
-                                                       onChange={acceptToggle}
-                                                       value={!!channel.pivot.accept_tracker}
-                                               />
-                                       </Form.Group>
-                               </Row>
-                       : null}
-                       {channel && episode && manageCrew ? <>
-                               <CrewManagement
-                                       channel={channel}
-                                       episode={episode}
-                                       manageCrew={manageCrew}
-                                       role="commentary"
-                               />
-                               <CrewManagement
-                                       channel={channel}
-                                       episode={episode}
-                                       manageCrew={manageCrew}
-                                       role="tracking"
-                               />
-                               <CrewManagement
-                                       channel={channel}
-                                       episode={episode}
-                                       manageCrew={manageCrew}
-                                       role="setup"
-                               />
-                       </> : null}
-               </Modal.Body>
-               <Modal.Footer className="justify-content-between">
-                       {onRemoveRestream ?
-                               <Button onClick={() => onRemoveRestream(episode, channel)} variant="outline-danger">
-                                       {t('button.remove')}
-                               </Button>
-                       : null}
-                       {onCancel ?
-                               <Button onClick={onCancel} variant="secondary">
-                                       {t('button.close')}
-                               </Button>
-                       : null}
-               </Modal.Footer>
-       </>;
-};
-
-RestreamEditForm.propTypes = {
-       channel: PropTypes.shape({
-               id: PropTypes.number,
-               pivot: PropTypes.shape({
-                       accept_comms: PropTypes.bool,
-                       accept_tracker: PropTypes.bool,
-               }),
-               title: PropTypes.string,
-       }),
-       editRestream: PropTypes.func,
-       episode: PropTypes.shape({
-               crew: PropTypes.arrayOf(PropTypes.shape({
-                       channel_id: PropTypes.number,
-                       role: PropTypes.string,
-               })),
-               event: PropTypes.shape({
-                       title: PropTypes.string,
-               }),
-               id: PropTypes.number,
-               players: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               start: PropTypes.string,
-       }),
-       manageCrew: PropTypes.func,
-       onCancel: PropTypes.func,
-       onRemoveRestream: PropTypes.func,
-};
-
-export default RestreamEditForm;
diff --git a/resources/js/components/episodes/RestreamEditForm.jsx b/resources/js/components/episodes/RestreamEditForm.jsx
new file mode 100644 (file)
index 0000000..84a3ea2
--- /dev/null
@@ -0,0 +1,136 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import CrewManagement from './CrewManagement';
+import ToggleSwitch from '../common/ToggleSwitch';
+import { getName } from '../../helpers/Crew';
+
+const RestreamEditForm = ({
+       channel,
+       editRestream,
+       episode,
+       manageCrew,
+       onCancel,
+       onRemoveRestream,
+}) => {
+       const { t } = useTranslation();
+
+       const acceptToggle = React.useCallback(e => {
+               editRestream({
+                       channel_id: channel.id,
+                       episode_id: episode.id,
+                       [e.target.name]: e.target.value,
+               });
+       }, [channel, editRestream, episode]);
+
+       return <>
+               <Modal.Body>
+                       {channel ?
+                               <div>
+                                       {channel.title}
+                               </div>
+                       : null}
+                       {episode ? <>
+                               <div>
+                                       {episode.event.title}
+                               </div>
+                               <div>
+                                       {t('episodes.startTime', { date: new Date(episode.start) })}
+                               </div>
+                               <div>
+                                       {episode.players.map(p => getName(p)).join(', ')}
+                               </div>
+                       </> : null}
+                       {channel && episode && editRestream ?
+                               <Row>
+                                       <Form.Group as={Col} sm={6} controlId="episodes.accept_comms">
+                                               <Form.Label className="d-block">
+                                                       {t('episodes.restreamDialog.acceptComms')}
+                                               </Form.Label>
+                                               <Form.Control
+                                                       as={ToggleSwitch}
+                                                       name="accept_comms"
+                                                       onChange={acceptToggle}
+                                                       value={!!channel.pivot.accept_comms}
+                                               />
+                                       </Form.Group>
+                                       <Form.Group as={Col} sm={6} controlId="episodes.accept_tracker">
+                                               <Form.Label className="d-block">
+                                                       {t('episodes.restreamDialog.acceptTracker')}
+                                               </Form.Label>
+                                               <Form.Control
+                                                       as={ToggleSwitch}
+                                                       name="accept_tracker"
+                                                       onChange={acceptToggle}
+                                                       value={!!channel.pivot.accept_tracker}
+                                               />
+                                       </Form.Group>
+                               </Row>
+                       : null}
+                       {channel && episode && manageCrew ? <>
+                               <CrewManagement
+                                       channel={channel}
+                                       episode={episode}
+                                       manageCrew={manageCrew}
+                                       role="commentary"
+                               />
+                               <CrewManagement
+                                       channel={channel}
+                                       episode={episode}
+                                       manageCrew={manageCrew}
+                                       role="tracking"
+                               />
+                               <CrewManagement
+                                       channel={channel}
+                                       episode={episode}
+                                       manageCrew={manageCrew}
+                                       role="setup"
+                               />
+                       </> : null}
+               </Modal.Body>
+               <Modal.Footer className="justify-content-between">
+                       {onRemoveRestream ?
+                               <Button onClick={() => onRemoveRestream(episode, channel)} variant="outline-danger">
+                                       {t('button.remove')}
+                               </Button>
+                       : null}
+                       {onCancel ?
+                               <Button onClick={onCancel} variant="secondary">
+                                       {t('button.close')}
+                               </Button>
+                       : null}
+               </Modal.Footer>
+       </>;
+};
+
+RestreamEditForm.propTypes = {
+       channel: PropTypes.shape({
+               id: PropTypes.number,
+               pivot: PropTypes.shape({
+                       accept_comms: PropTypes.bool,
+                       accept_tracker: PropTypes.bool,
+               }),
+               title: PropTypes.string,
+       }),
+       editRestream: PropTypes.func,
+       episode: PropTypes.shape({
+               crew: PropTypes.arrayOf(PropTypes.shape({
+                       channel_id: PropTypes.number,
+                       role: PropTypes.string,
+               })),
+               event: PropTypes.shape({
+                       title: PropTypes.string,
+               }),
+               id: PropTypes.number,
+               players: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               start: PropTypes.string,
+       }),
+       manageCrew: PropTypes.func,
+       onCancel: PropTypes.func,
+       onRemoveRestream: PropTypes.func,
+};
+
+export default RestreamEditForm;
diff --git a/resources/js/components/events/Detail.js b/resources/js/components/events/Detail.js
deleted file mode 100644 (file)
index 6589548..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from '../common/Icon';
-import RawHTML from '../common/RawHTML';
-import { hasConcluded } from '../../helpers/Event';
-import { getTranslation } from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const Detail = ({ actions, event }) => {
-       const { t } = useTranslation();
-
-       return <>
-               <div className="d-flex align-items-center justify-content-between">
-                       <h1>
-                               {(event.description && getTranslation(event.description, 'title', i18n.language))
-                                       || event.title}
-                       </h1>
-                       {event.description && actions.editContent ?
-                               <Button
-                                       className="ms-3"
-                                       onClick={() => actions.editContent(event.description)}
-                                       size="sm"
-                                       title={t('button.edit')}
-                                       variant="outline-secondary"
-                               >
-                                       <Icon.EDIT title="" />
-                               </Button>
-                       : null}
-               </div>
-               {event.description ?
-                       <RawHTML html={getTranslation(event.description, 'description', i18n.language)} />
-               : null}
-               {hasConcluded(event) ?
-                       <Alert variant="info">
-                               {t('events.concluded')}
-                       </Alert>
-               : null}
-       </>;
-};
-
-Detail.propTypes = {
-       actions: PropTypes.shape({
-               editContent: PropTypes.func,
-       }),
-       event: PropTypes.shape({
-               description: PropTypes.shape({
-               }),
-               end: PropTypes.string,
-               title: PropTypes.string,
-       }),
-};
-
-export default Detail;
diff --git a/resources/js/components/events/Detail.jsx b/resources/js/components/events/Detail.jsx
new file mode 100644 (file)
index 0000000..6589548
--- /dev/null
@@ -0,0 +1,56 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../common/Icon';
+import RawHTML from '../common/RawHTML';
+import { hasConcluded } from '../../helpers/Event';
+import { getTranslation } from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const Detail = ({ actions, event }) => {
+       const { t } = useTranslation();
+
+       return <>
+               <div className="d-flex align-items-center justify-content-between">
+                       <h1>
+                               {(event.description && getTranslation(event.description, 'title', i18n.language))
+                                       || event.title}
+                       </h1>
+                       {event.description && actions.editContent ?
+                               <Button
+                                       className="ms-3"
+                                       onClick={() => actions.editContent(event.description)}
+                                       size="sm"
+                                       title={t('button.edit')}
+                                       variant="outline-secondary"
+                               >
+                                       <Icon.EDIT title="" />
+                               </Button>
+                       : null}
+               </div>
+               {event.description ?
+                       <RawHTML html={getTranslation(event.description, 'description', i18n.language)} />
+               : null}
+               {hasConcluded(event) ?
+                       <Alert variant="info">
+                               {t('events.concluded')}
+                       </Alert>
+               : null}
+       </>;
+};
+
+Detail.propTypes = {
+       actions: PropTypes.shape({
+               editContent: PropTypes.func,
+       }),
+       event: PropTypes.shape({
+               description: PropTypes.shape({
+               }),
+               end: PropTypes.string,
+               title: PropTypes.string,
+       }),
+};
+
+export default Detail;
diff --git a/resources/js/components/events/Item.js b/resources/js/components/events/Item.js
deleted file mode 100644 (file)
index 9217d56..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-import moment from 'moment';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { Link } from 'react-router-dom';
-
-import RawHTML from '../common/RawHTML';
-import {
-       getLink,
-} from '../../helpers/Event';
-import {
-       getTranslation,
-} from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const Item = ({ event }) => {
-       const { t } = useTranslation();
-
-       const style = React.useMemo(() => {
-               if (event && event.corner) {
-                       return {
-                               backgroundImage: `url(${event.corner})`,
-                       };
-               }
-               return null;
-       }, [event && event.corner]);
-
-       return <li className="events-item my-3 p-2 pb-5 border rounded" style={style}>
-               <h3>
-                       <Link to={getLink(event)}>
-                               {(event.description && getTranslation(event.description, 'title', i18n.language))
-                                       || event.title}
-                       </Link>
-               </h3>
-               <div className="d-flex align-items-start justify-content-start">
-                       {event.start || event.end ?
-                               <div className="event-pane">
-                                       {event.start ? <>
-                                               <div><small>{t('events.start')}</small></div>
-                                               <div className="mb-2">{moment(event.start).format('LL')}</div>
-                                       </> : null}
-                                       {event.end ? <>
-                                               <div><small>{t('events.end')}</small></div>
-                                               <div className="mb-2">{moment(event.end).format('LL')}</div>
-                                       </> : null}
-                               </div>
-                       : null}
-                       {event.description?
-                               <div>
-                                       <RawHTML
-                                               html={getTranslation(event.description, 'description', i18n.language)}
-                                       />
-                               </div>
-                       : null}
-               </div>
-       </li>;
-};
-
-Item.propTypes = {
-       event: PropTypes.shape({
-               corner: PropTypes.string,
-               description: PropTypes.shape({
-               }),
-               end: PropTypes.string,
-               id: PropTypes.number,
-               name: PropTypes.string,
-               start: PropTypes.string,
-               title: PropTypes.string,
-       }),
-};
-
-export default Item;
diff --git a/resources/js/components/events/Item.jsx b/resources/js/components/events/Item.jsx
new file mode 100644 (file)
index 0000000..9217d56
--- /dev/null
@@ -0,0 +1,72 @@
+import moment from 'moment';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { Link } from 'react-router-dom';
+
+import RawHTML from '../common/RawHTML';
+import {
+       getLink,
+} from '../../helpers/Event';
+import {
+       getTranslation,
+} from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const Item = ({ event }) => {
+       const { t } = useTranslation();
+
+       const style = React.useMemo(() => {
+               if (event && event.corner) {
+                       return {
+                               backgroundImage: `url(${event.corner})`,
+                       };
+               }
+               return null;
+       }, [event && event.corner]);
+
+       return <li className="events-item my-3 p-2 pb-5 border rounded" style={style}>
+               <h3>
+                       <Link to={getLink(event)}>
+                               {(event.description && getTranslation(event.description, 'title', i18n.language))
+                                       || event.title}
+                       </Link>
+               </h3>
+               <div className="d-flex align-items-start justify-content-start">
+                       {event.start || event.end ?
+                               <div className="event-pane">
+                                       {event.start ? <>
+                                               <div><small>{t('events.start')}</small></div>
+                                               <div className="mb-2">{moment(event.start).format('LL')}</div>
+                                       </> : null}
+                                       {event.end ? <>
+                                               <div><small>{t('events.end')}</small></div>
+                                               <div className="mb-2">{moment(event.end).format('LL')}</div>
+                                       </> : null}
+                               </div>
+                       : null}
+                       {event.description?
+                               <div>
+                                       <RawHTML
+                                               html={getTranslation(event.description, 'description', i18n.language)}
+                                       />
+                               </div>
+                       : null}
+               </div>
+       </li>;
+};
+
+Item.propTypes = {
+       event: PropTypes.shape({
+               corner: PropTypes.string,
+               description: PropTypes.shape({
+               }),
+               end: PropTypes.string,
+               id: PropTypes.number,
+               name: PropTypes.string,
+               start: PropTypes.string,
+               title: PropTypes.string,
+       }),
+};
+
+export default Item;
diff --git a/resources/js/components/events/List.js b/resources/js/components/events/List.js
deleted file mode 100644 (file)
index b509477..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Item from './Item';
-
-const List = ({ events }) => <ul className="event-list">
-       {events.map(event =>
-               <Item event={event} key={event.id} />
-       )}
-</ul>;
-
-List.propTypes = {
-       events: PropTypes.arrayOf(PropTypes.shape({
-               id: PropTypes.number,
-               name: PropTypes.string,
-       })),
-};
-
-export default List;
diff --git a/resources/js/components/events/List.jsx b/resources/js/components/events/List.jsx
new file mode 100644 (file)
index 0000000..b509477
--- /dev/null
@@ -0,0 +1,19 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Item from './Item';
+
+const List = ({ events }) => <ul className="event-list">
+       {events.map(event =>
+               <Item event={event} key={event.id} />
+       )}
+</ul>;
+
+List.propTypes = {
+       events: PropTypes.arrayOf(PropTypes.shape({
+               id: PropTypes.number,
+               name: PropTypes.string,
+       })),
+};
+
+export default List;
diff --git a/resources/js/components/map/Buttons.js b/resources/js/components/map/Buttons.js
deleted file mode 100644 (file)
index b07fba6..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Form } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import { useOpenSeadragon } from './OpenSeadragon';
-
-const Buttons = ({ setUWOverlay, uwOverlay }) => {
-       const { activeMap, setActiveMap } = useOpenSeadragon();
-       const { t } = useTranslation();
-
-       return <div className="mt-5">
-               <div className="button-bar">
-                       {['lw', 'dw', 'sp', 'uw', 'uw2'].map(map =>
-                               <Button
-                                       active={activeMap === map}
-                                       key={map}
-                                       onClick={() => setActiveMap(map)}
-                                       title={t(`map.${map}Long`)}
-                                       variant="outline-secondary"
-                               >
-                                       {t(`map.${map}Short`)}
-                               </Button>
-                       )}
-               </div>
-               {activeMap === 'uw' ?
-                       <div className="mt-2">
-                               <Form.Check
-                                       checked={uwOverlay}
-                                       id="toggle-uw-overlay"
-                                       inline
-                                       onChange={e => setUWOverlay(e.target.checked)}
-                                       type="checkbox"
-                               />
-                               <Form.Label className="mt-0" htmlFor="toggle-uw-overlay">
-                                       {t('map.uwOverlay')}
-                               </Form.Label>
-                       </div>
-               : null}
-       </div>;
-};
-
-Buttons.propTypes = {
-       setUWOverlay: PropTypes.func,
-       uwOverlay: PropTypes.bool,
-};
-
-export default Buttons;
diff --git a/resources/js/components/map/Buttons.jsx b/resources/js/components/map/Buttons.jsx
new file mode 100644 (file)
index 0000000..b07fba6
--- /dev/null
@@ -0,0 +1,48 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Form } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import { useOpenSeadragon } from './OpenSeadragon';
+
+const Buttons = ({ setUWOverlay, uwOverlay }) => {
+       const { activeMap, setActiveMap } = useOpenSeadragon();
+       const { t } = useTranslation();
+
+       return <div className="mt-5">
+               <div className="button-bar">
+                       {['lw', 'dw', 'sp', 'uw', 'uw2'].map(map =>
+                               <Button
+                                       active={activeMap === map}
+                                       key={map}
+                                       onClick={() => setActiveMap(map)}
+                                       title={t(`map.${map}Long`)}
+                                       variant="outline-secondary"
+                               >
+                                       {t(`map.${map}Short`)}
+                               </Button>
+                       )}
+               </div>
+               {activeMap === 'uw' ?
+                       <div className="mt-2">
+                               <Form.Check
+                                       checked={uwOverlay}
+                                       id="toggle-uw-overlay"
+                                       inline
+                                       onChange={e => setUWOverlay(e.target.checked)}
+                                       type="checkbox"
+                               />
+                               <Form.Label className="mt-0" htmlFor="toggle-uw-overlay">
+                                       {t('map.uwOverlay')}
+                               </Form.Label>
+                       </div>
+               : null}
+       </div>;
+};
+
+Buttons.propTypes = {
+       setUWOverlay: PropTypes.func,
+       uwOverlay: PropTypes.bool,
+};
+
+export default Buttons;
diff --git a/resources/js/components/map/Item.js b/resources/js/components/map/Item.js
deleted file mode 100644 (file)
index 3fde3d1..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-import { Link, useSearchParams } from 'react-router-dom';
-
-import { useOpenSeadragon } from './OpenSeadragon';
-import Icon from '../common/Icon';
-import Rulesets from '../techniques/Rulesets';
-import {
-       getLink,
-       getRelations,
-       getTranslation,
-       hasRelations,
-       sorted,
-} from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const Item = ({ pin }) => {
-       const { viewer } = useOpenSeadragon();
-       const [, setSearchParams] = useSearchParams();
-       const { t } = useTranslation();
-
-       const goToLocation = React.useCallback(pin => {
-               setSearchParams({ x: pin.x, y: pin.y, z: 4 });
-               if (viewer && viewer.element) {
-                       viewer.element.scrollIntoView();
-               }
-       }, [viewer]);
-
-       return <li className="d-flex align-items-start justify-content-between">
-               <div className="flex-grow-1">
-                               {pin.technique.type === 'location' ? <>
-                                       <h2>{getTranslation(pin.technique, 'title', i18n.language)}</h2>
-                                       <p>{getTranslation(pin.technique, 'short', i18n.language)}</p>
-                                       {hasRelations(pin.technique, 'related') ?
-                                               sorted(getRelations(pin.technique, 'related')).map(r =>
-                                                       <div
-                                                               className="d-flex align-items-start justify-content-between"
-                                                               key={r.id}
-                                                       >
-                                                               <div className="me-auto">
-                                                                       <h3>
-                                                                               <Link to={getLink(r)}>
-                                                                                       {getTranslation(r, 'title', i18n.language)}
-                                                                               </Link>
-                                                                       </h3>
-                                                                       <p>{getTranslation(r, 'short', i18n.language)}</p>
-                                                               </div>
-                                                               {r.rulesets ?
-                                                                       <Rulesets technique={r} />
-                                                               : null}
-                                                       </div>
-                                               )
-                                       : null}
-                               </> : <div className="d-flex align-items-start justify-content-between">
-                                       <div className="flex-grow-1">
-                                               <h2>
-                                                       <Link to={getLink(pin.technique)}>
-                                                               {getTranslation(pin.technique, 'title', i18n.language)}
-                                                       </Link>
-                                               </h2>
-                                               <p>{getTranslation(pin.technique, 'short', i18n.language)}</p>
-                                       </div>
-                                       {pin.technique.rulesets ?
-                                               <Rulesets technique={pin.technique} />
-                                       : null}
-                               </div>}
-                       </div>
-               <Button
-                       className="m-2"
-                       onClick={() => goToLocation(pin)}
-                       title={t('map.goToLocation')}
-                       variant="outline-secondary"
-               >
-                       <Icon.CROSSHAIRS title="" />
-               </Button>
-       </li>;
-};
-
-Item.propTypes = {
-       pin: PropTypes.shape({
-               technique: PropTypes.shape({
-                       rulesets: PropTypes.shape({
-                       }),
-                       type: PropTypes.string,
-               }),
-               x: PropTypes.number,
-               y: PropTypes.number,
-       }),
-};
-
-export default Item;
diff --git a/resources/js/components/map/Item.jsx b/resources/js/components/map/Item.jsx
new file mode 100644 (file)
index 0000000..3fde3d1
--- /dev/null
@@ -0,0 +1,93 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import { Link, useSearchParams } from 'react-router-dom';
+
+import { useOpenSeadragon } from './OpenSeadragon';
+import Icon from '../common/Icon';
+import Rulesets from '../techniques/Rulesets';
+import {
+       getLink,
+       getRelations,
+       getTranslation,
+       hasRelations,
+       sorted,
+} from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const Item = ({ pin }) => {
+       const { viewer } = useOpenSeadragon();
+       const [, setSearchParams] = useSearchParams();
+       const { t } = useTranslation();
+
+       const goToLocation = React.useCallback(pin => {
+               setSearchParams({ x: pin.x, y: pin.y, z: 4 });
+               if (viewer && viewer.element) {
+                       viewer.element.scrollIntoView();
+               }
+       }, [viewer]);
+
+       return <li className="d-flex align-items-start justify-content-between">
+               <div className="flex-grow-1">
+                               {pin.technique.type === 'location' ? <>
+                                       <h2>{getTranslation(pin.technique, 'title', i18n.language)}</h2>
+                                       <p>{getTranslation(pin.technique, 'short', i18n.language)}</p>
+                                       {hasRelations(pin.technique, 'related') ?
+                                               sorted(getRelations(pin.technique, 'related')).map(r =>
+                                                       <div
+                                                               className="d-flex align-items-start justify-content-between"
+                                                               key={r.id}
+                                                       >
+                                                               <div className="me-auto">
+                                                                       <h3>
+                                                                               <Link to={getLink(r)}>
+                                                                                       {getTranslation(r, 'title', i18n.language)}
+                                                                               </Link>
+                                                                       </h3>
+                                                                       <p>{getTranslation(r, 'short', i18n.language)}</p>
+                                                               </div>
+                                                               {r.rulesets ?
+                                                                       <Rulesets technique={r} />
+                                                               : null}
+                                                       </div>
+                                               )
+                                       : null}
+                               </> : <div className="d-flex align-items-start justify-content-between">
+                                       <div className="flex-grow-1">
+                                               <h2>
+                                                       <Link to={getLink(pin.technique)}>
+                                                               {getTranslation(pin.technique, 'title', i18n.language)}
+                                                       </Link>
+                                               </h2>
+                                               <p>{getTranslation(pin.technique, 'short', i18n.language)}</p>
+                                       </div>
+                                       {pin.technique.rulesets ?
+                                               <Rulesets technique={pin.technique} />
+                                       : null}
+                               </div>}
+                       </div>
+               <Button
+                       className="m-2"
+                       onClick={() => goToLocation(pin)}
+                       title={t('map.goToLocation')}
+                       variant="outline-secondary"
+               >
+                       <Icon.CROSSHAIRS title="" />
+               </Button>
+       </li>;
+};
+
+Item.propTypes = {
+       pin: PropTypes.shape({
+               technique: PropTypes.shape({
+                       rulesets: PropTypes.shape({
+                       }),
+                       type: PropTypes.string,
+               }),
+               x: PropTypes.number,
+               y: PropTypes.number,
+       }),
+};
+
+export default Item;
diff --git a/resources/js/components/map/List.js b/resources/js/components/map/List.js
deleted file mode 100644 (file)
index 7b66630..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import { Container } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Item from './Item';
-import { useOpenSeadragon } from './OpenSeadragon';
-import { compareTranslation } from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const List = () => {
-       const { pins } = useOpenSeadragon();
-       const { t } = useTranslation();
-
-       const sortedPins = React.useMemo(() => {
-               const compare = compareTranslation('title', i18n.language);
-               return pins.sort((a, b) => compare(a.technique, b.technique));
-       }, [pins, i18n.language]);
-
-       if (!pins || !pins.length) return null;
-
-       return <Container className="mt-3">
-               <h2>{t('map.onThisMap')}</h2>
-               <ul className="pin-list">
-                       {sortedPins.map(pin =>
-                               <Item key={pin.id} pin={pin} />
-                       )}
-               </ul>
-       </Container>;
-};
-
-export default List;
diff --git a/resources/js/components/map/List.jsx b/resources/js/components/map/List.jsx
new file mode 100644 (file)
index 0000000..7b66630
--- /dev/null
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Container } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Item from './Item';
+import { useOpenSeadragon } from './OpenSeadragon';
+import { compareTranslation } from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const List = () => {
+       const { pins } = useOpenSeadragon();
+       const { t } = useTranslation();
+
+       const sortedPins = React.useMemo(() => {
+               const compare = compareTranslation('title', i18n.language);
+               return pins.sort((a, b) => compare(a.technique, b.technique));
+       }, [pins, i18n.language]);
+
+       if (!pins || !pins.length) return null;
+
+       return <Container className="mt-3">
+               <h2>{t('map.onThisMap')}</h2>
+               <ul className="pin-list">
+                       {sortedPins.map(pin =>
+                               <Item key={pin.id} pin={pin} />
+                       )}
+               </ul>
+       </Container>;
+};
+
+export default List;
diff --git a/resources/js/components/map/OpenSeadragon.js b/resources/js/components/map/OpenSeadragon.js
deleted file mode 100644 (file)
index 36ddec1..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-import axios from 'axios';
-import OpenSeadragon from 'openseadragon';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useNavigate, useParams } from 'react-router';
-import { createSearchParams, useSearchParams } from 'react-router-dom';
-
-export const Context = React.createContext({});
-
-export const useOpenSeadragon = () => React.useContext(Context);
-
-export const Provider = React.forwardRef(({ children }, ref) => {
-       const { activeMap } = useParams();
-       const navigate = useNavigate();
-       const [searchParams, setSearchParams] = useSearchParams();
-       const [pins, setPins] = React.useState([]);
-       const [viewer, setViewer] = React.useState(null);
-
-       const storePosition = React.useCallback(() => {
-               if (!viewer || !viewer.viewport) return;
-               const center = viewer.viewport.getCenter();
-               const zoom = viewer.viewport.getZoom();
-               setSearchParams({ x: center.x, y: center.y, z: zoom }, { replace: true });
-       }, [setSearchParams, viewer]);
-
-       const setActiveMap = React.useCallback(map => {
-               if (viewer && viewer.viewport) {
-                       const center = viewer.viewport.getCenter();
-                       const zoom = viewer.viewport.getZoom();
-                       const params = { x: center.x, y: center.y, z: zoom };
-                       navigate(
-                               { pathname: `../${map}`, search: `?${createSearchParams(params)}` },
-                               { replace: true },
-                       );
-               } else {
-                       navigate(`../${map}`, { replace: true });
-               }
-       }, [navigate, viewer]);
-
-       React.useEffect(() => {
-               if (!viewer || !viewer.viewport) return;
-               if (searchParams.has('x') && searchParams.has('y')) {
-                       viewer.viewport.panTo(new OpenSeadragon.Point(
-                               parseFloat(searchParams.get('x')),
-                               parseFloat(searchParams.get('y')),
-                       ));
-               }
-               if (searchParams.has('z')) {
-                       viewer.viewport.zoomTo(parseFloat(searchParams.get('z')));
-               }
-       }, [searchParams, viewer]);
-
-       React.useEffect(() => {
-               if (!ref.current) return;
-
-               const v = OpenSeadragon({
-                       element: ref.current,
-                       preserveViewport: true,
-                       sequenceMode: true,
-                       showNavigator: true,
-                       showNavigationControl: false,
-                       showSequenceControl: false,
-                       tileSources: [
-                               new OpenSeadragon.DziTileSource({
-                                       width: 8192,
-                                       height: 8192,
-                                       tileSize: 256,
-                                       tileOverlap: 0,
-                                       minLevel: 8,
-                                       maxLevel: 13,
-                                       tilesUrl: '/media/alttp/map/lw_files/',
-                                       fileFormat: 'png',
-                               }), new OpenSeadragon.DziTileSource({
-                                       width: 8192,
-                                       height: 8192,
-                                       tileSize: 256,
-                                       tileOverlap: 0,
-                                       minLevel: 8,
-                                       maxLevel: 13,
-                                       tilesUrl: '/media/alttp/map/dw_files/',
-                                       fileFormat: 'png',
-                               }), new OpenSeadragon.DziTileSource({
-                                       width: 8192,
-                                       height: 4096,
-                                       tileSize: 256,
-                                       tileOverlap: 0,
-                                       minLevel: 8,
-                                       maxLevel: 13,
-                                       tilesUrl: '/media/alttp/map/sp_files/',
-                                       fileFormat: 'png',
-                               }), new OpenSeadragon.DziTileSource({
-                                       width: 16384,
-                                       height: 16384,
-                                       tileSize: 256,
-                                       tileOverlap: 0,
-                                       minLevel: 8,
-                                       maxLevel: 14,
-                                       tilesUrl: '/media/alttp/map/uw_files/',
-                                       fileFormat: 'png',
-                               }), new OpenSeadragon.DziTileSource({
-                                       width: 16384,
-                                       height: 3072,
-                                       tileSize: 256,
-                                       tileOverlap: 0,
-                                       minLevel: 8,
-                                       maxLevel: 14,
-                                       tilesUrl: '/media/alttp/map/uw2_files/',
-                                       fileFormat: 'png',
-                               }),
-                       ],
-               });
-               v.addHandler('canvas-nonprimary-press', e => {
-                       if (e.button === 3) {
-                               navigate(-1);
-                       } else if (e.button === 4) {
-                               navigate(1);
-                       }
-               });
-               setViewer(v);
-               return () => {
-                       v.destroy();
-               };
-       }, [ref.current]);
-
-       React.useEffect(() => {
-               if (!viewer) return;
-               switch (activeMap) {
-                       case 'lw':
-                               viewer.goToPage(0);
-                               break;
-                       case 'dw':
-                               viewer.goToPage(1);
-                               break;
-                       case 'sp':
-                               viewer.goToPage(2);
-                               break;
-                       case 'uw':
-                               viewer.goToPage(3);
-                               break;
-                       case 'uw2':
-                               viewer.goToPage(4);
-                               break;
-               }
-               const controller = new AbortController();
-               axios.get(`/api/markers/${activeMap}`, {
-                       signal: controller.signal,
-               }).then(response => {
-                       setPins(response.data || []);
-               }).catch(e => {
-                       if (!axios.isCancel(e)) {
-                               console.error(e);
-                       }
-               });
-               return () => {
-                       controller.abort();
-               };
-       }, [activeMap, viewer]);
-
-       return <Context.Provider value={{ activeMap, pins, setActiveMap, storePosition, viewer }}>
-               {children}
-       </Context.Provider>;
-});
-
-Provider.displayName = 'OpenSeadragonProvider';
-
-Provider.propTypes = {
-       children: PropTypes.node,
-};
-
-export default Provider;
diff --git a/resources/js/components/map/OpenSeadragon.jsx b/resources/js/components/map/OpenSeadragon.jsx
new file mode 100644 (file)
index 0000000..55e9638
--- /dev/null
@@ -0,0 +1,171 @@
+import axios from 'axios';
+import OpenSeadragon from 'openseadragon';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useNavigate, useParams } from 'react-router';
+import { createSearchParams, useSearchParams } from 'react-router-dom';
+
+export const Context = React.createContext({});
+
+export const useOpenSeadragon = () => React.useContext(Context);
+
+export const Provider = ({ children, containerRef }) => {
+       const { activeMap } = useParams();
+       const navigate = useNavigate();
+       const [searchParams, setSearchParams] = useSearchParams();
+       const [pins, setPins] = React.useState([]);
+       const [viewer, setViewer] = React.useState(null);
+
+       const storePosition = React.useCallback(() => {
+               if (!viewer || !viewer.viewport) return;
+               const center = viewer.viewport.getCenter();
+               const zoom = viewer.viewport.getZoom();
+               setSearchParams({ x: center.x, y: center.y, z: zoom }, { replace: true });
+       }, [setSearchParams, viewer]);
+
+       const setActiveMap = React.useCallback(map => {
+               if (viewer && viewer.viewport) {
+                       const center = viewer.viewport.getCenter();
+                       const zoom = viewer.viewport.getZoom();
+                       const params = { x: center.x, y: center.y, z: zoom };
+                       navigate(
+                               { pathname: `../${map}`, search: `?${createSearchParams(params)}` },
+                               { replace: true },
+                       );
+               } else {
+                       navigate(`../${map}`, { replace: true });
+               }
+       }, [navigate, viewer]);
+
+       React.useEffect(() => {
+               if (!viewer || !viewer.viewport) return;
+               if (searchParams.has('x') && searchParams.has('y')) {
+                       viewer.viewport.panTo(new OpenSeadragon.Point(
+                               parseFloat(searchParams.get('x')),
+                               parseFloat(searchParams.get('y')),
+                       ));
+               }
+               if (searchParams.has('z')) {
+                       viewer.viewport.zoomTo(parseFloat(searchParams.get('z')));
+               }
+       }, [searchParams, viewer]);
+
+       React.useEffect(() => {
+               if (!containerRef.current) return;
+
+               const v = OpenSeadragon({
+                       element: containerRef.current,
+                       preserveViewport: true,
+                       sequenceMode: true,
+                       showNavigator: true,
+                       showNavigationControl: false,
+                       showSequenceControl: false,
+                       tileSources: [
+                               new OpenSeadragon.DziTileSource({
+                                       width: 8192,
+                                       height: 8192,
+                                       tileSize: 256,
+                                       tileOverlap: 0,
+                                       minLevel: 8,
+                                       maxLevel: 13,
+                                       tilesUrl: '/media/alttp/map/lw_files/',
+                                       fileFormat: 'png',
+                               }), new OpenSeadragon.DziTileSource({
+                                       width: 8192,
+                                       height: 8192,
+                                       tileSize: 256,
+                                       tileOverlap: 0,
+                                       minLevel: 8,
+                                       maxLevel: 13,
+                                       tilesUrl: '/media/alttp/map/dw_files/',
+                                       fileFormat: 'png',
+                               }), new OpenSeadragon.DziTileSource({
+                                       width: 8192,
+                                       height: 4096,
+                                       tileSize: 256,
+                                       tileOverlap: 0,
+                                       minLevel: 8,
+                                       maxLevel: 13,
+                                       tilesUrl: '/media/alttp/map/sp_files/',
+                                       fileFormat: 'png',
+                               }), new OpenSeadragon.DziTileSource({
+                                       width: 16384,
+                                       height: 16384,
+                                       tileSize: 256,
+                                       tileOverlap: 0,
+                                       minLevel: 8,
+                                       maxLevel: 14,
+                                       tilesUrl: '/media/alttp/map/uw_files/',
+                                       fileFormat: 'png',
+                               }), new OpenSeadragon.DziTileSource({
+                                       width: 16384,
+                                       height: 3072,
+                                       tileSize: 256,
+                                       tileOverlap: 0,
+                                       minLevel: 8,
+                                       maxLevel: 14,
+                                       tilesUrl: '/media/alttp/map/uw2_files/',
+                                       fileFormat: 'png',
+                               }),
+                       ],
+               });
+               v.addHandler('canvas-nonprimary-press', e => {
+                       if (e.button === 3) {
+                               navigate(-1);
+                       } else if (e.button === 4) {
+                               navigate(1);
+                       }
+               });
+               setViewer(v);
+               return () => {
+                       v.destroy();
+               };
+       }, [containerRef.current]);
+
+       React.useEffect(() => {
+               if (!viewer) return;
+               switch (activeMap) {
+                       case 'lw':
+                               viewer.goToPage(0);
+                               break;
+                       case 'dw':
+                               viewer.goToPage(1);
+                               break;
+                       case 'sp':
+                               viewer.goToPage(2);
+                               break;
+                       case 'uw':
+                               viewer.goToPage(3);
+                               break;
+                       case 'uw2':
+                               viewer.goToPage(4);
+                               break;
+               }
+               const controller = new AbortController();
+               axios.get(`/api/markers/${activeMap}`, {
+                       signal: controller.signal,
+               }).then(response => {
+                       setPins(response.data || []);
+               }).catch(e => {
+                       if (!axios.isCancel(e)) {
+                               console.error(e);
+                       }
+               });
+               return () => {
+                       controller.abort();
+               };
+       }, [activeMap, viewer]);
+
+       return <Context.Provider value={{ activeMap, pins, setActiveMap, storePosition, viewer }}>
+               {children}
+       </Context.Provider>;
+};
+
+Provider.displayName = 'OpenSeadragonProvider';
+
+Provider.propTypes = {
+       children: PropTypes.node,
+       containerRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
+};
+
+export default Provider;
diff --git a/resources/js/components/map/Overlay.js b/resources/js/components/map/Overlay.js
deleted file mode 100644 (file)
index 747d0e4..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-import OpenSeadragon from 'openseadragon';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { createPortal } from 'react-dom';
-
-import { useOpenSeadragon } from './OpenSeadragon';
-
-const Overlay = ({ children, height, onClick, page, width, x, y }) => {
-       const { viewer } = useOpenSeadragon();
-       const [element] = React.useState(document.createElement('div'));
-
-       React.useEffect(() => {
-               if (!viewer) return;
-               const add = () => {
-                       if (width && height) {
-                               viewer.addOverlay(
-                                       element,
-                                       new OpenSeadragon.Rect(x, y, width, height),
-                               );
-                       } else {
-                               viewer.addOverlay(
-                                       element,
-                                       new OpenSeadragon.Point(x, y),
-                                       OpenSeadragon.Placement.CENTER,
-                               );
-                       }
-                       if (onClick) {
-                               new OpenSeadragon.MouseTracker({
-                                       element,
-                                       clickHandler: onClick,
-                               });
-                       }
-               };
-               const addPage = () => {
-                       if (viewer.currentPage() === page) {
-                               add();
-                       }
-               };
-               if (typeof page !== 'undefined') {
-                       viewer.addHandler('page', addPage);
-                       return () => {
-                               viewer.removeHandler('page', addPage);
-                               try {
-                                       viewer.removeOverlay(element);
-                               } catch (e) {
-                                       // bug in OSD?
-                                       console.error(e);
-                               }
-                       };
-               }
-               if (viewer.isOpen()) {
-                       add();
-               } else {
-                       viewer.addHandler('open', add);
-                       return () => {
-                               viewer.removeHandler('open', add);
-                               try {
-                                       viewer.removeOverlay(element);
-                               } catch (e) {
-                                       // bug in OSD?
-                                       console.error(e);
-                               }
-                       };
-               }
-       }, [onClick, height, page, viewer, width, x, y]);
-
-       return createPortal(children, element);
-};
-
-Overlay.propTypes = {
-       children: PropTypes.node,
-       height: PropTypes.number,
-       onClick: PropTypes.func,
-       page: PropTypes.number,
-       width: PropTypes.number,
-       x: PropTypes.number,
-       y: PropTypes.number,
-};
-
-export default Overlay;
diff --git a/resources/js/components/map/Overlay.jsx b/resources/js/components/map/Overlay.jsx
new file mode 100644 (file)
index 0000000..747d0e4
--- /dev/null
@@ -0,0 +1,80 @@
+import OpenSeadragon from 'openseadragon';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { createPortal } from 'react-dom';
+
+import { useOpenSeadragon } from './OpenSeadragon';
+
+const Overlay = ({ children, height, onClick, page, width, x, y }) => {
+       const { viewer } = useOpenSeadragon();
+       const [element] = React.useState(document.createElement('div'));
+
+       React.useEffect(() => {
+               if (!viewer) return;
+               const add = () => {
+                       if (width && height) {
+                               viewer.addOverlay(
+                                       element,
+                                       new OpenSeadragon.Rect(x, y, width, height),
+                               );
+                       } else {
+                               viewer.addOverlay(
+                                       element,
+                                       new OpenSeadragon.Point(x, y),
+                                       OpenSeadragon.Placement.CENTER,
+                               );
+                       }
+                       if (onClick) {
+                               new OpenSeadragon.MouseTracker({
+                                       element,
+                                       clickHandler: onClick,
+                               });
+                       }
+               };
+               const addPage = () => {
+                       if (viewer.currentPage() === page) {
+                               add();
+                       }
+               };
+               if (typeof page !== 'undefined') {
+                       viewer.addHandler('page', addPage);
+                       return () => {
+                               viewer.removeHandler('page', addPage);
+                               try {
+                                       viewer.removeOverlay(element);
+                               } catch (e) {
+                                       // bug in OSD?
+                                       console.error(e);
+                               }
+                       };
+               }
+               if (viewer.isOpen()) {
+                       add();
+               } else {
+                       viewer.addHandler('open', add);
+                       return () => {
+                               viewer.removeHandler('open', add);
+                               try {
+                                       viewer.removeOverlay(element);
+                               } catch (e) {
+                                       // bug in OSD?
+                                       console.error(e);
+                               }
+                       };
+               }
+       }, [onClick, height, page, viewer, width, x, y]);
+
+       return createPortal(children, element);
+};
+
+Overlay.propTypes = {
+       children: PropTypes.node,
+       height: PropTypes.number,
+       onClick: PropTypes.func,
+       page: PropTypes.number,
+       width: PropTypes.number,
+       x: PropTypes.number,
+       y: PropTypes.number,
+};
+
+export default Overlay;
diff --git a/resources/js/components/map/Pin.js b/resources/js/components/map/Pin.js
deleted file mode 100644 (file)
index 9d9b471..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Link, useNavigate } from 'react-router-dom';
-
-import { useOpenSeadragon } from './OpenSeadragon';
-import Overlay from './Overlay';
-import Popover from './Popover';
-import Icon from '../common/Icon';
-import ZeldaIcon from '../common/ZeldaIcon';
-import { getLink, getTranslation } from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const Pin = ({ pin }) => {
-       const { storePosition } = useOpenSeadragon();
-       const [showPopover, setShowPopover] = React.useState(false);
-       const ref = React.useRef();
-
-       const navigate = useNavigate();
-
-       const onClick = React.useCallback((e) => {
-               if (ref.current && ref.current.contains(e.originalTarget)) {
-                       if (e.originalTarget.tagName === 'A') {
-                               storePosition();
-                               navigate(new URL(e.originalTarget.href).pathname);
-                       }
-               } else {
-                       if (pin.technique.type === 'location') {
-                               setShowPopover(s => !s);
-                       } else {
-                               storePosition();
-                               navigate(getLink(pin.technique));
-                       }
-               }
-       }, [pin]);
-
-       const title = React.useMemo(() => {
-               return getTranslation(pin.technique, 'title', i18n.language);
-       }, [pin, i18n.language]);
-
-       return <Overlay onClick={onClick} x={pin.x} y={pin.y}>
-               <div className="map-pin">
-                       <Link to={getLink(pin.technique)}>
-                               {pin.marker ?
-                                       <ZeldaIcon title={title} name={pin.marker} />
-                               :
-                                       <Icon.PIN title={title} />
-                               }
-                       </Link>
-                       {pin.technique.type === 'location' ?
-                               <div ref={ref}>
-                                       <Popover show={showPopover} technique={pin.technique} />
-                               </div>
-                       : null}
-               </div>
-       </Overlay>;
-};
-
-Pin.propTypes = {
-       pin: PropTypes.shape({
-               marker: PropTypes.string,
-               technique: PropTypes.shape({
-                       type: PropTypes.string,
-               }),
-               x: PropTypes.number,
-               y: PropTypes.number,
-       }),
-};
-
-export default Pin;
diff --git a/resources/js/components/map/Pin.jsx b/resources/js/components/map/Pin.jsx
new file mode 100644 (file)
index 0000000..9d9b471
--- /dev/null
@@ -0,0 +1,69 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Link, useNavigate } from 'react-router-dom';
+
+import { useOpenSeadragon } from './OpenSeadragon';
+import Overlay from './Overlay';
+import Popover from './Popover';
+import Icon from '../common/Icon';
+import ZeldaIcon from '../common/ZeldaIcon';
+import { getLink, getTranslation } from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const Pin = ({ pin }) => {
+       const { storePosition } = useOpenSeadragon();
+       const [showPopover, setShowPopover] = React.useState(false);
+       const ref = React.useRef();
+
+       const navigate = useNavigate();
+
+       const onClick = React.useCallback((e) => {
+               if (ref.current && ref.current.contains(e.originalTarget)) {
+                       if (e.originalTarget.tagName === 'A') {
+                               storePosition();
+                               navigate(new URL(e.originalTarget.href).pathname);
+                       }
+               } else {
+                       if (pin.technique.type === 'location') {
+                               setShowPopover(s => !s);
+                       } else {
+                               storePosition();
+                               navigate(getLink(pin.technique));
+                       }
+               }
+       }, [pin]);
+
+       const title = React.useMemo(() => {
+               return getTranslation(pin.technique, 'title', i18n.language);
+       }, [pin, i18n.language]);
+
+       return <Overlay onClick={onClick} x={pin.x} y={pin.y}>
+               <div className="map-pin">
+                       <Link to={getLink(pin.technique)}>
+                               {pin.marker ?
+                                       <ZeldaIcon title={title} name={pin.marker} />
+                               :
+                                       <Icon.PIN title={title} />
+                               }
+                       </Link>
+                       {pin.technique.type === 'location' ?
+                               <div ref={ref}>
+                                       <Popover show={showPopover} technique={pin.technique} />
+                               </div>
+                       : null}
+               </div>
+       </Overlay>;
+};
+
+Pin.propTypes = {
+       pin: PropTypes.shape({
+               marker: PropTypes.string,
+               technique: PropTypes.shape({
+                       type: PropTypes.string,
+               }),
+               x: PropTypes.number,
+               y: PropTypes.number,
+       }),
+};
+
+export default Pin;
diff --git a/resources/js/components/map/Pins.js b/resources/js/components/map/Pins.js
deleted file mode 100644 (file)
index 8b37ee9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-
-import { useOpenSeadragon } from './OpenSeadragon';
-import Pin from './Pin';
-
-const Pins = () => {
-       const { pins } = useOpenSeadragon();
-
-       return pins.map(pin =>
-               <Pin key={pin.id} pin={pin} />
-       );
-};
-
-export default Pins;
diff --git a/resources/js/components/map/Pins.jsx b/resources/js/components/map/Pins.jsx
new file mode 100644 (file)
index 0000000..8b37ee9
--- /dev/null
@@ -0,0 +1,14 @@
+import React from 'react';
+
+import { useOpenSeadragon } from './OpenSeadragon';
+import Pin from './Pin';
+
+const Pins = () => {
+       const { pins } = useOpenSeadragon();
+
+       return pins.map(pin =>
+               <Pin key={pin.id} pin={pin} />
+       );
+};
+
+export default Pins;
diff --git a/resources/js/components/map/Popover.js b/resources/js/components/map/Popover.js
deleted file mode 100644 (file)
index 7fbbcef..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Card, ListGroup } from 'react-bootstrap';
-import { Link } from 'react-router-dom';
-
-import ZeldaIcon from '../common/ZeldaIcon';
-
-import {
-       getLink,
-       getRelations,
-       getTranslation,
-       hasRelations,
-       sorted,
-} from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const Popover = ({ show, technique }) =>
-       <div className={`map-popover ${show ? 'shown' : 'hidden'}`}>
-               <Card bg="dark">
-                       <Card.Header>
-                               <Card.Title>
-                                       {getTranslation(technique, 'title', i18n.language)}
-                               </Card.Title>
-                       </Card.Header>
-                       {technique.short ?
-                               <Card.Body>
-                                       <Card.Text>
-                                               {getTranslation(technique, 'short', i18n.language)}
-                                       </Card.Text>
-                               </Card.Body>
-                       : null}
-                       {hasRelations(technique, 'related') ?
-                               <ListGroup variant="flush">
-                                       {sorted(getRelations(technique, 'related')).map(r =>
-                                               <ListGroup.Item
-                                                       key={r.id}
-                                                       title={getTranslation(r, 'short', i18n.language)}
-                                               >
-                                                       <Link to={getLink(r)}>
-                                                               {r.title_icons ?
-                                                                       <span className="tech-title-icons">
-                                                                               {r.title_icons.map(icon =>
-                                                                                       <ZeldaIcon key={icon} name={icon} />
-                                                                               )}
-                                                                       </span>
-                                                               : null}
-                                                               {getTranslation(r, 'title', i18n.language)}
-                                                       </Link>
-                                               </ListGroup.Item>
-                                       )}
-                               </ListGroup>
-                       : null}
-               </Card>
-       </div>;
-
-Popover.propTypes = {
-       show: PropTypes.bool,
-       technique: PropTypes.shape({
-               short: PropTypes.string,
-       }),
-};
-
-export default Popover;
diff --git a/resources/js/components/map/Popover.jsx b/resources/js/components/map/Popover.jsx
new file mode 100644 (file)
index 0000000..7fbbcef
--- /dev/null
@@ -0,0 +1,63 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Card, ListGroup } from 'react-bootstrap';
+import { Link } from 'react-router-dom';
+
+import ZeldaIcon from '../common/ZeldaIcon';
+
+import {
+       getLink,
+       getRelations,
+       getTranslation,
+       hasRelations,
+       sorted,
+} from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const Popover = ({ show, technique }) =>
+       <div className={`map-popover ${show ? 'shown' : 'hidden'}`}>
+               <Card bg="dark">
+                       <Card.Header>
+                               <Card.Title>
+                                       {getTranslation(technique, 'title', i18n.language)}
+                               </Card.Title>
+                       </Card.Header>
+                       {technique.short ?
+                               <Card.Body>
+                                       <Card.Text>
+                                               {getTranslation(technique, 'short', i18n.language)}
+                                       </Card.Text>
+                               </Card.Body>
+                       : null}
+                       {hasRelations(technique, 'related') ?
+                               <ListGroup variant="flush">
+                                       {sorted(getRelations(technique, 'related')).map(r =>
+                                               <ListGroup.Item
+                                                       key={r.id}
+                                                       title={getTranslation(r, 'short', i18n.language)}
+                                               >
+                                                       <Link to={getLink(r)}>
+                                                               {r.title_icons ?
+                                                                       <span className="tech-title-icons">
+                                                                               {r.title_icons.map(icon =>
+                                                                                       <ZeldaIcon key={icon} name={icon} />
+                                                                               )}
+                                                                       </span>
+                                                               : null}
+                                                               {getTranslation(r, 'title', i18n.language)}
+                                                       </Link>
+                                               </ListGroup.Item>
+                                       )}
+                               </ListGroup>
+                       : null}
+               </Card>
+       </div>;
+
+Popover.propTypes = {
+       show: PropTypes.bool,
+       technique: PropTypes.shape({
+               short: PropTypes.string,
+       }),
+};
+
+export default Popover;
diff --git a/resources/js/components/map/UWSuperTiles.js b/resources/js/components/map/UWSuperTiles.js
deleted file mode 100644 (file)
index 83404ac..0000000
+++ /dev/null
@@ -1,505 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useSearchParams } from 'react-router-dom';
-
-import Overlay from './Overlay';
-import { useOpenSeadragon } from './OpenSeadragon';
-
-const dropMap = {
-       '00': '10',
-       '03': '02',
-       '05': '05',
-       '06': '05',
-       '07': '17',
-       '08': '07',
-       '09': '4B',
-       '0A': '09',
-       '0B': '6A',
-       '0D': '0B',
-       '0F': '01',
-       '10': '01',
-       '12': '0D',
-       '13': '0D',
-       '14': '0D',
-       '17': '27',
-       '18': '12',
-       '19': '07',
-       '1E': '3E',
-       '20': '01',
-       '21': '0D',
-       '22': '0D',
-       '23': '0D',
-       '24': '08',
-       '27': '31',
-       '29': '07',
-       '2A': '07',
-       '2C': '12',
-       '2D': '06',
-       '2E': '06',
-       '2F': '02',
-       '31': '77',
-       '33': '08',
-       '35': '08',
-       '36': '08',
-       '37': '08',
-       '39': '29',
-       '3A': '0A',
-       '3C': '0E',
-       '3D': '96',
-       '43': '0A',
-       '44': '0A',
-       '46': '09',
-       '47': '07',
-       '48': '07',
-       '49': '07',
-       '4B': '09',
-       '4D': 'A6',
-       '4F': 'BE',
-       '54': '34',
-       '55': '09',
-       '56': '09',
-       '57': '09',
-       '58': '09',
-       '59': '07',
-       '5A': '0E',
-       '5B': '0E',
-       '5E': '7E',
-       '65': 'AC',
-       '67': '09',
-       '68': '07',
-       '6D': '0B',
-       '73': '05',
-       '74': '05',
-       '75': '08',
-       '77': 'A7',
-       '78': '9D',
-       '79': '9D',
-       '7A': '9D',
-       '7B': '9D',
-       '7C': '0E',
-       '7D': '9B',
-       '7E': '9E',
-       '81': '05',
-       '82': '05',
-       '83': '05',
-       '84': '05',
-       '85': '05',
-       '88': 'A9',
-       '89': 'A9',
-       '8A': '0E',
-       '8B': '0E',
-       '8C': '1C',
-       '8D': '0B',
-       '8F': '0C',
-       '90': '0C',
-       '92': '0C',
-       '94': '0E',
-       '95': '0E',
-       '97': 'D1',
-       '9A': '7D',
-       '9B': '7D',
-       '9C': '0E',
-       '9D': '7B',
-       '9E': 'BE',
-       '9F': '0C',
-       'A1': '0C',
-       'A3': '0C',
-       'A4': '0E',
-       'A7': '17',
-       'A8': '05',
-       'A9': '89',
-       'AA': '0A',
-       'AC': '0B',
-       'AF': '02',
-       'B1': 'B2',
-       'B2': '0C',
-       'B3': '0D',
-       'B7': '0D',
-       'B8': '05',
-       'B9': '05',
-       'BA': '0A',
-       'BB': '0A',
-       'BD': '4F',
-       'BE': '4F',
-       'BF': '02',
-       'C1': '0C',
-       'C2': '0C',
-       'C3': '0D',
-       'C5': '0D',
-       'C6': '0D',
-       'C7': '05',
-       'C8': '05',
-       'C9': '0A',
-       'CA': '0B',
-       'CB': '0B',
-       'CC': '0B',
-       'CD': 'DE',
-       'CE': 'DE',
-       'D1': 'B1',
-       'D3': '05',
-       'D4': '05',
-       'D5': '0D',
-       'D6': '0D',
-       'D7': '05',
-       'D8': '05',
-       'D9': '05',
-       'DB': '0B',
-       'DC': '0B',
-       'DD': '06',
-       'DE': '06',
-       'E1': '06',
-       'E2': '06',
-       'E3': '14',
-       'E4': '06',
-       'E5': '06',
-       'E6': '06',
-       'E7': '06',
-       'E8': 'F8',
-       'E9': 'FA',
-       'EA': 'FA',
-       'EB': 'FB',
-       'EC': 'FD',
-       'ED': 'FD',
-       'EE': 'FE',
-       'EF': 'FF',
-       'F0': '06',
-       'F1': '06',
-       'F4': '06',
-       'F5': '06',
-       'F9': '06',
-       'FE': '06',
-};
-
-const strongEG = [
-       '08',
-       '0C',
-       '15',
-       '2F',
-       '40',
-       '51',
-       '52',
-       '59',
-       '5B',
-       '60',
-       '62',
-       '66',
-       '71',
-       '72',
-       '81',
-       'A2',
-       'A8',
-       'A9',
-       'AA',
-       'B2',
-       'B3',
-       'B9',
-       'C2',
-       'C3',
-       'CB',
-       'CC',
-       'DB',
-       'DC',
-       'DF',
-       'E1',
-       'E3',
-       'FA',
-];
-
-const weakEG = [
-       '07',
-       '0A',
-       '16',
-       '28',
-       '2A',
-       '2B',
-       '34',
-       '35',
-       '36',
-       '37',
-       '3A',
-       '4D',
-       '55',
-       '61',
-       '76',
-       '99',
-       'A0',
-       'C9',
-       'E2',
-       'E4',
-       'F0',
-       'FD',
-       'FE',
-];
-
-const kick = [
-       '1B',
-       '29',
-       '3E',
-       '43',
-       '97',
-];
-
-const dark = [
-       '0B',
-       '19',
-       '21',
-       '22',
-       '32',
-       '41',
-       '42',
-       '69',
-       '6A',
-       '92',
-       '93',
-       'B5',
-       'BA',
-       'C0',
-       'D0',
-       'E5',
-       'E6',
-       'E7',
-       'F0',
-       'F1',
-];
-
-const camera = {
-       '00': ['x', 'y'],
-       '01': ['y'],
-       '02': ['y'],
-       '07': ['x', 'y'],
-       '0A': ['x', 'y'],
-       '0C': ['x', 'y'],
-       '0D': ['x', 'y'],
-       '0E': ['yu'],
-       '10': ['x'],
-       '11': ['x'],
-       '12': ['x', 'y'],
-       '13': ['x'],
-       '14': ['x', 'y'],
-       '15': ['x', 'y'],
-       '16': ['y'],
-       '17': ['x', 'y'],
-       '18': ['x'],
-       '19': ['xr'],
-       '1A': ['xl'],
-       '1B': ['yu'],
-       '1D': ['y'],
-       '1F': ['yu'],
-       '20': ['x', 'y'],
-       '21': ['y'],
-       '22': ['y'],
-       '26': ['yd'],
-       '27': ['x', 'y'],
-       '28': ['x', 'y'],
-       '2A': ['x', 'y'],
-       '2B': ['xl'],
-       '2F': ['yd'],
-       '31': ['yu'],
-       '32': ['x', 'y'],
-       '34': ['x', 'y'],
-       '35': ['y'],
-       '36': ['x', 'y'],
-       '37': ['y'],
-       '38': ['x'],
-       '39': ['yu'],
-       '3A': ['x', 'y'],
-       '3B': ['x'],
-       '3C': ['x', 'y'],
-       '3E': ['yd'],
-       '3F': ['yu'],
-       '40': ['xl'],
-       '41': ['x', 'y'],
-       '42': ['y'],
-       '43': ['yu'],
-       '44': ['xr'],
-       '45': ['xr'],
-       '46': ['y'],
-       '49': ['xr'],
-       '4A': ['y'],
-       '4B': ['yd'],
-       '4C': ['x'],
-       '4D': ['x', 'y'],
-       '4E': ['yd'],
-       '50': ['x'],
-       '51': ['x', 'y'],
-       '52': ['xl', 'yd'],
-       '53': ['xr'],
-       '54': ['x', 'y'],
-       '55': ['y'],
-       '56': ['xr'],
-       '58': ['xr'],
-       '59': ['x'],
-       '5B': ['x'],
-       '5C': ['yu'],
-       '60': ['x'],
-       '61': ['x', 'y'],
-       '62': ['x', 'y'],
-       '63': ['xr'],
-       '64': ['yu'],
-       '65': ['yu'],
-       '66': ['yd'],
-       '67': ['x'],
-       '68': ['x', 'y'],
-       '6A': ['x'],
-       '6B': ['yu'],
-       '6D': ['xr'],
-       '72': ['y'],
-       '74': ['y'],
-       '75': ['xr'],
-       '76': ['xl'],
-       '77': ['x', 'y'],
-       '7B': ['yu'],
-       '7C': ['x'],
-       '7D': ['yu'],
-       '7E': ['xr'],
-       '7F': ['xr'],
-       '80': ['y'],
-       '81': ['x', 'y'],
-       '82': ['x', 'y'],
-       '83': ['xr'],
-       '84': ['x', 'y'],
-       '85': ['xl'],
-       '89': ['y'],
-       '8B': ['xl'],
-       '8D': ['xr'],
-       '91': ['x'],
-       '92': ['xr'],
-       '93': ['yu'],
-       '95': ['x'],
-       '96': ['xl'],
-       '97': ['xr'],
-       '98': ['yd'],
-       '99': ['yd'],
-       '9B': ['yd'],
-       '9C': ['x', 'y'],
-       '9D': ['yd'],
-       'A0': ['y'],
-       'A1': ['xr', 'yu'],
-       'A2': ['x', 'y'],
-       'A3': ['x'],
-       'A5': ['yd'],
-       'A6': ['x', 'y'],
-       'A7': ['yd'],
-       'A8': ['xr'],
-       'A9': ['x', 'y'],
-       'AA': ['xl'],
-       'B1': ['xr'],
-       'B2': ['yu'],
-       'B3': ['x'],
-       'B4': ['x', 'y'],
-       'B5': ['x', 'y'],
-       'B7': ['x'],
-       'B8': ['x'],
-       'B9': ['x', 'y'],
-       'BB': ['xl'],
-       'BC': ['xr'],
-       'BE': ['xl'],
-       'C0': ['xl'],
-       'C2': ['x', 'y'],
-       'C3': ['x'],
-       'C4': ['x', 'y'],
-       'C5': ['x'],
-       'C6': ['x', 'y'],
-       'C7': ['x', 'y'],
-       'C9': ['y'],
-       'CB': ['x', 'y'],
-       'CC': ['x', 'y'],
-       'D0': ['xl'],
-       'D2': ['xr'],
-       'D5': ['x'],
-       'D6': ['x'],
-       'D8': ['xl'],
-       'D9': ['yu'],
-       'DA': ['yu'],
-       'DB': ['x', 'y'],
-       'DC': ['x', 'y'],
-       'DF': ['yd'],
-       'E1': ['x'],
-       'E2': ['x'],
-       'E4': ['x'],
-       'E5': ['x', 'y'],
-       'E6': ['xr', 'yd'],
-       'E7': ['xr', 'yu'],
-       'E8': ['x', 'yu'],
-       'EA': ['xl', 'yu'],
-       'EB': ['x'],
-       'ED': ['x', 'yu'],
-       'EE': ['x', 'y'],
-       'EF': ['yd'],
-       'F0': ['x', 'y'],
-       'F1': ['x', 'y'],
-       'F8': ['x', 'y'],
-       'F9': ['xr', 'yd'],
-       'FA': ['x', 'y'],
-       'FB': ['xr', 'yd'],
-       'FD': ['x', 'y'],
-       'FE': ['xr'],
-       'FF': ['yd'],
-};
-
-const getClassName = key => {
-       const classNames = [];
-       if (strongEG.includes(key)) {
-               classNames.push('strong-eg');
-       }
-       if (weakEG.includes(key)) {
-               classNames.push('weak-eg');
-       }
-       if (kick.includes(key)) {
-               classNames.push('kick');
-       }
-       if (dark.includes(key)) {
-               classNames.push('dark');
-       }
-       if (camera[key]) {
-               camera[key].forEach(c => {
-                       classNames.push(`cam-${c}`);
-               });
-       }
-       return classNames.join(' ');
-};
-
-const UWSuperTiles = ({ show }) => {
-       const { storePosition, viewer } = useOpenSeadragon();
-       const [, setSearchParams] = useSearchParams();
-
-       const onClick = React.useCallback(e => {
-               if (e.originalTarget.tagName !== 'A') return;
-               if (e.originalTarget.className !== 'cell-link') return;
-               const key = e.originalTarget.dataset.key;
-
-               const x = (parseInt(key[1], 16) + 0.5) / 16;
-               const y = (parseInt(key[0], 16) + 0.5) / 16;
-               if (viewer && viewer.viewport) {
-                       storePosition();
-                       setSearchParams({ x, y, z: 4 });
-                       viewer.element.scrollIntoView();
-               }
-       }, [storePosition, viewer]);
-
-       return <Overlay onClick={onClick} page={3} x={0} y={0} width={1} height={1}>
-               <div className={`uw-super-tiles ${show ? '' : 'd-none'}`}>
-                       {[...Array(16).keys()].map(x =>
-                               [...Array(16).keys()].map(y => {
-                                       const key = `${x.toString(16).toUpperCase()}${y.toString(16).toUpperCase()}`;
-                                       return <div className={getClassName(key)} key={key}>
-                                               <p className="cell-id">{key}</p>
-                                               {dropMap[key] ?
-                                                       <p className="cell-drop">
-                                                               <a className="cell-link" data-key={dropMap[key]}>
-                                                                       {`▶ ${dropMap[key]}`}
-                                                               </a>
-                                                       </p>
-                                               : null}
-                                       </div>;
-                               })
-                       )}
-               </div>
-       </Overlay>;
-};
-
-UWSuperTiles.propTypes = {
-       show: PropTypes.bool,
-};
-
-export default UWSuperTiles;
diff --git a/resources/js/components/map/UWSuperTiles.jsx b/resources/js/components/map/UWSuperTiles.jsx
new file mode 100644 (file)
index 0000000..83404ac
--- /dev/null
@@ -0,0 +1,505 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useSearchParams } from 'react-router-dom';
+
+import Overlay from './Overlay';
+import { useOpenSeadragon } from './OpenSeadragon';
+
+const dropMap = {
+       '00': '10',
+       '03': '02',
+       '05': '05',
+       '06': '05',
+       '07': '17',
+       '08': '07',
+       '09': '4B',
+       '0A': '09',
+       '0B': '6A',
+       '0D': '0B',
+       '0F': '01',
+       '10': '01',
+       '12': '0D',
+       '13': '0D',
+       '14': '0D',
+       '17': '27',
+       '18': '12',
+       '19': '07',
+       '1E': '3E',
+       '20': '01',
+       '21': '0D',
+       '22': '0D',
+       '23': '0D',
+       '24': '08',
+       '27': '31',
+       '29': '07',
+       '2A': '07',
+       '2C': '12',
+       '2D': '06',
+       '2E': '06',
+       '2F': '02',
+       '31': '77',
+       '33': '08',
+       '35': '08',
+       '36': '08',
+       '37': '08',
+       '39': '29',
+       '3A': '0A',
+       '3C': '0E',
+       '3D': '96',
+       '43': '0A',
+       '44': '0A',
+       '46': '09',
+       '47': '07',
+       '48': '07',
+       '49': '07',
+       '4B': '09',
+       '4D': 'A6',
+       '4F': 'BE',
+       '54': '34',
+       '55': '09',
+       '56': '09',
+       '57': '09',
+       '58': '09',
+       '59': '07',
+       '5A': '0E',
+       '5B': '0E',
+       '5E': '7E',
+       '65': 'AC',
+       '67': '09',
+       '68': '07',
+       '6D': '0B',
+       '73': '05',
+       '74': '05',
+       '75': '08',
+       '77': 'A7',
+       '78': '9D',
+       '79': '9D',
+       '7A': '9D',
+       '7B': '9D',
+       '7C': '0E',
+       '7D': '9B',
+       '7E': '9E',
+       '81': '05',
+       '82': '05',
+       '83': '05',
+       '84': '05',
+       '85': '05',
+       '88': 'A9',
+       '89': 'A9',
+       '8A': '0E',
+       '8B': '0E',
+       '8C': '1C',
+       '8D': '0B',
+       '8F': '0C',
+       '90': '0C',
+       '92': '0C',
+       '94': '0E',
+       '95': '0E',
+       '97': 'D1',
+       '9A': '7D',
+       '9B': '7D',
+       '9C': '0E',
+       '9D': '7B',
+       '9E': 'BE',
+       '9F': '0C',
+       'A1': '0C',
+       'A3': '0C',
+       'A4': '0E',
+       'A7': '17',
+       'A8': '05',
+       'A9': '89',
+       'AA': '0A',
+       'AC': '0B',
+       'AF': '02',
+       'B1': 'B2',
+       'B2': '0C',
+       'B3': '0D',
+       'B7': '0D',
+       'B8': '05',
+       'B9': '05',
+       'BA': '0A',
+       'BB': '0A',
+       'BD': '4F',
+       'BE': '4F',
+       'BF': '02',
+       'C1': '0C',
+       'C2': '0C',
+       'C3': '0D',
+       'C5': '0D',
+       'C6': '0D',
+       'C7': '05',
+       'C8': '05',
+       'C9': '0A',
+       'CA': '0B',
+       'CB': '0B',
+       'CC': '0B',
+       'CD': 'DE',
+       'CE': 'DE',
+       'D1': 'B1',
+       'D3': '05',
+       'D4': '05',
+       'D5': '0D',
+       'D6': '0D',
+       'D7': '05',
+       'D8': '05',
+       'D9': '05',
+       'DB': '0B',
+       'DC': '0B',
+       'DD': '06',
+       'DE': '06',
+       'E1': '06',
+       'E2': '06',
+       'E3': '14',
+       'E4': '06',
+       'E5': '06',
+       'E6': '06',
+       'E7': '06',
+       'E8': 'F8',
+       'E9': 'FA',
+       'EA': 'FA',
+       'EB': 'FB',
+       'EC': 'FD',
+       'ED': 'FD',
+       'EE': 'FE',
+       'EF': 'FF',
+       'F0': '06',
+       'F1': '06',
+       'F4': '06',
+       'F5': '06',
+       'F9': '06',
+       'FE': '06',
+};
+
+const strongEG = [
+       '08',
+       '0C',
+       '15',
+       '2F',
+       '40',
+       '51',
+       '52',
+       '59',
+       '5B',
+       '60',
+       '62',
+       '66',
+       '71',
+       '72',
+       '81',
+       'A2',
+       'A8',
+       'A9',
+       'AA',
+       'B2',
+       'B3',
+       'B9',
+       'C2',
+       'C3',
+       'CB',
+       'CC',
+       'DB',
+       'DC',
+       'DF',
+       'E1',
+       'E3',
+       'FA',
+];
+
+const weakEG = [
+       '07',
+       '0A',
+       '16',
+       '28',
+       '2A',
+       '2B',
+       '34',
+       '35',
+       '36',
+       '37',
+       '3A',
+       '4D',
+       '55',
+       '61',
+       '76',
+       '99',
+       'A0',
+       'C9',
+       'E2',
+       'E4',
+       'F0',
+       'FD',
+       'FE',
+];
+
+const kick = [
+       '1B',
+       '29',
+       '3E',
+       '43',
+       '97',
+];
+
+const dark = [
+       '0B',
+       '19',
+       '21',
+       '22',
+       '32',
+       '41',
+       '42',
+       '69',
+       '6A',
+       '92',
+       '93',
+       'B5',
+       'BA',
+       'C0',
+       'D0',
+       'E5',
+       'E6',
+       'E7',
+       'F0',
+       'F1',
+];
+
+const camera = {
+       '00': ['x', 'y'],
+       '01': ['y'],
+       '02': ['y'],
+       '07': ['x', 'y'],
+       '0A': ['x', 'y'],
+       '0C': ['x', 'y'],
+       '0D': ['x', 'y'],
+       '0E': ['yu'],
+       '10': ['x'],
+       '11': ['x'],
+       '12': ['x', 'y'],
+       '13': ['x'],
+       '14': ['x', 'y'],
+       '15': ['x', 'y'],
+       '16': ['y'],
+       '17': ['x', 'y'],
+       '18': ['x'],
+       '19': ['xr'],
+       '1A': ['xl'],
+       '1B': ['yu'],
+       '1D': ['y'],
+       '1F': ['yu'],
+       '20': ['x', 'y'],
+       '21': ['y'],
+       '22': ['y'],
+       '26': ['yd'],
+       '27': ['x', 'y'],
+       '28': ['x', 'y'],
+       '2A': ['x', 'y'],
+       '2B': ['xl'],
+       '2F': ['yd'],
+       '31': ['yu'],
+       '32': ['x', 'y'],
+       '34': ['x', 'y'],
+       '35': ['y'],
+       '36': ['x', 'y'],
+       '37': ['y'],
+       '38': ['x'],
+       '39': ['yu'],
+       '3A': ['x', 'y'],
+       '3B': ['x'],
+       '3C': ['x', 'y'],
+       '3E': ['yd'],
+       '3F': ['yu'],
+       '40': ['xl'],
+       '41': ['x', 'y'],
+       '42': ['y'],
+       '43': ['yu'],
+       '44': ['xr'],
+       '45': ['xr'],
+       '46': ['y'],
+       '49': ['xr'],
+       '4A': ['y'],
+       '4B': ['yd'],
+       '4C': ['x'],
+       '4D': ['x', 'y'],
+       '4E': ['yd'],
+       '50': ['x'],
+       '51': ['x', 'y'],
+       '52': ['xl', 'yd'],
+       '53': ['xr'],
+       '54': ['x', 'y'],
+       '55': ['y'],
+       '56': ['xr'],
+       '58': ['xr'],
+       '59': ['x'],
+       '5B': ['x'],
+       '5C': ['yu'],
+       '60': ['x'],
+       '61': ['x', 'y'],
+       '62': ['x', 'y'],
+       '63': ['xr'],
+       '64': ['yu'],
+       '65': ['yu'],
+       '66': ['yd'],
+       '67': ['x'],
+       '68': ['x', 'y'],
+       '6A': ['x'],
+       '6B': ['yu'],
+       '6D': ['xr'],
+       '72': ['y'],
+       '74': ['y'],
+       '75': ['xr'],
+       '76': ['xl'],
+       '77': ['x', 'y'],
+       '7B': ['yu'],
+       '7C': ['x'],
+       '7D': ['yu'],
+       '7E': ['xr'],
+       '7F': ['xr'],
+       '80': ['y'],
+       '81': ['x', 'y'],
+       '82': ['x', 'y'],
+       '83': ['xr'],
+       '84': ['x', 'y'],
+       '85': ['xl'],
+       '89': ['y'],
+       '8B': ['xl'],
+       '8D': ['xr'],
+       '91': ['x'],
+       '92': ['xr'],
+       '93': ['yu'],
+       '95': ['x'],
+       '96': ['xl'],
+       '97': ['xr'],
+       '98': ['yd'],
+       '99': ['yd'],
+       '9B': ['yd'],
+       '9C': ['x', 'y'],
+       '9D': ['yd'],
+       'A0': ['y'],
+       'A1': ['xr', 'yu'],
+       'A2': ['x', 'y'],
+       'A3': ['x'],
+       'A5': ['yd'],
+       'A6': ['x', 'y'],
+       'A7': ['yd'],
+       'A8': ['xr'],
+       'A9': ['x', 'y'],
+       'AA': ['xl'],
+       'B1': ['xr'],
+       'B2': ['yu'],
+       'B3': ['x'],
+       'B4': ['x', 'y'],
+       'B5': ['x', 'y'],
+       'B7': ['x'],
+       'B8': ['x'],
+       'B9': ['x', 'y'],
+       'BB': ['xl'],
+       'BC': ['xr'],
+       'BE': ['xl'],
+       'C0': ['xl'],
+       'C2': ['x', 'y'],
+       'C3': ['x'],
+       'C4': ['x', 'y'],
+       'C5': ['x'],
+       'C6': ['x', 'y'],
+       'C7': ['x', 'y'],
+       'C9': ['y'],
+       'CB': ['x', 'y'],
+       'CC': ['x', 'y'],
+       'D0': ['xl'],
+       'D2': ['xr'],
+       'D5': ['x'],
+       'D6': ['x'],
+       'D8': ['xl'],
+       'D9': ['yu'],
+       'DA': ['yu'],
+       'DB': ['x', 'y'],
+       'DC': ['x', 'y'],
+       'DF': ['yd'],
+       'E1': ['x'],
+       'E2': ['x'],
+       'E4': ['x'],
+       'E5': ['x', 'y'],
+       'E6': ['xr', 'yd'],
+       'E7': ['xr', 'yu'],
+       'E8': ['x', 'yu'],
+       'EA': ['xl', 'yu'],
+       'EB': ['x'],
+       'ED': ['x', 'yu'],
+       'EE': ['x', 'y'],
+       'EF': ['yd'],
+       'F0': ['x', 'y'],
+       'F1': ['x', 'y'],
+       'F8': ['x', 'y'],
+       'F9': ['xr', 'yd'],
+       'FA': ['x', 'y'],
+       'FB': ['xr', 'yd'],
+       'FD': ['x', 'y'],
+       'FE': ['xr'],
+       'FF': ['yd'],
+};
+
+const getClassName = key => {
+       const classNames = [];
+       if (strongEG.includes(key)) {
+               classNames.push('strong-eg');
+       }
+       if (weakEG.includes(key)) {
+               classNames.push('weak-eg');
+       }
+       if (kick.includes(key)) {
+               classNames.push('kick');
+       }
+       if (dark.includes(key)) {
+               classNames.push('dark');
+       }
+       if (camera[key]) {
+               camera[key].forEach(c => {
+                       classNames.push(`cam-${c}`);
+               });
+       }
+       return classNames.join(' ');
+};
+
+const UWSuperTiles = ({ show }) => {
+       const { storePosition, viewer } = useOpenSeadragon();
+       const [, setSearchParams] = useSearchParams();
+
+       const onClick = React.useCallback(e => {
+               if (e.originalTarget.tagName !== 'A') return;
+               if (e.originalTarget.className !== 'cell-link') return;
+               const key = e.originalTarget.dataset.key;
+
+               const x = (parseInt(key[1], 16) + 0.5) / 16;
+               const y = (parseInt(key[0], 16) + 0.5) / 16;
+               if (viewer && viewer.viewport) {
+                       storePosition();
+                       setSearchParams({ x, y, z: 4 });
+                       viewer.element.scrollIntoView();
+               }
+       }, [storePosition, viewer]);
+
+       return <Overlay onClick={onClick} page={3} x={0} y={0} width={1} height={1}>
+               <div className={`uw-super-tiles ${show ? '' : 'd-none'}`}>
+                       {[...Array(16).keys()].map(x =>
+                               [...Array(16).keys()].map(y => {
+                                       const key = `${x.toString(16).toUpperCase()}${y.toString(16).toUpperCase()}`;
+                                       return <div className={getClassName(key)} key={key}>
+                                               <p className="cell-id">{key}</p>
+                                               {dropMap[key] ?
+                                                       <p className="cell-drop">
+                                                               <a className="cell-link" data-key={dropMap[key]}>
+                                                                       {`▶ ${dropMap[key]}`}
+                                                               </a>
+                                                       </p>
+                                               : null}
+                                       </div>;
+                               })
+                       )}
+               </div>
+       </Overlay>;
+};
+
+UWSuperTiles.propTypes = {
+       show: PropTypes.bool,
+};
+
+export default UWSuperTiles;
diff --git a/resources/js/components/map/Viewer.js b/resources/js/components/map/Viewer.js
deleted file mode 100644 (file)
index 473c179..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-import OpenSeadragon from 'openseadragon';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-const Viewer = () => {
-       const [viewer, setViewer] = React.useState(null);
-
-       const container = React.useRef();
-       const { t } = useTranslation();
-
-       React.useEffect(() => {
-               if (!container.current) return;
-
-               const v = OpenSeadragon({
-                       element: container.current,
-                       preserveViewport: true,
-                       sequenceMode: true,
-                       showNavigator: true,
-                       showNavigationControl: false,
-                       showSequenceControl: false,
-                       //tileSources: [
-                       //      new OpenSeadragon.DziTileSource({
-                       //              width: 8192,
-                       //              height: 8192,
-                       //              tileSize: 256,
-                       //              tileOverlap: 0,
-                       //              minLevel: 8,
-                       //              maxLevel: 13,
-                       //              tilesUrl: '/media/alttp/map/lw_files/',
-                       //              fileFormat: 'png',
-                       //      }), new OpenSeadragon.DziTileSource({
-                       //              width: 8192,
-                       //              height: 8192,
-                       //              tileSize: 256,
-                       //              tileOverlap: 0,
-                       //              minLevel: 8,
-                       //              maxLevel: 13,
-                       //              tilesUrl: '/media/alttp/map/dw_files/',
-                       //              fileFormat: 'png',
-                       //      }), new OpenSeadragon.DziTileSource({
-                       //              width: 8192,
-                       //              height: 8192,
-                       //              tileSize: 256,
-                       //              tileOverlap: 0,
-                       //              minLevel: 8,
-                       //              maxLevel: 13,
-                       //              tilesUrl: '/media/alttp/map/sp_files/',
-                       //              fileFormat: 'png',
-                       //      }), new OpenSeadragon.DziTileSource({
-                       //              width: 16384,
-                       //              height: 16384,
-                       //              tileSize: 256,
-                       //              tileOverlap: 0,
-                       //              minLevel: 8,
-                       //              maxLevel: 14,
-                       //              tilesUrl: '/media/alttp/map/uw_files/',
-                       //              fileFormat: 'png',
-                       //      }),
-                       //],
-               });
-               setViewer(v);
-               return () => {
-                       v.destroy();
-               };
-       }, [container.current]);
-
-       const goToPage = React.useCallback((p) => {
-               if (viewer) viewer.goToPage(p);
-       }, [viewer]);
-
-       return <>
-               <div className="d-flex align-items-center justify-content-between">
-                       <div className="button-bar">
-                               <Button
-                                       onClick={() => goToPage(0)}
-                                       title={t('map.lwLong')}
-                                       variant="outline-secondary"
-                               >
-                                       {t('map.lwShort')}
-                               </Button>
-                               <Button
-                                       onClick={() => goToPage(1)}
-                                       title={t('map.dwLong')}
-                                       variant="outline-secondary"
-                               >
-                                       {t('map.dwShort')}
-                               </Button>
-                               <Button
-                                       onClick={() => goToPage(2)}
-                                       title={t('map.spLong')}
-                                       variant="outline-secondary"
-                               >
-                                       {t('map.spShort')}
-                               </Button>
-                               <Button
-                                       onClick={() => goToPage(3)}
-                                       title={t('map.uwLong')}
-                                       variant="outline-secondary"
-                               >
-                                       {t('map.uwShort')}
-                               </Button>
-                       </div>
-               </div>
-               <div ref={container} style={{ height: '80vh' }} />
-       </>;
-};
-
-export default Viewer;
diff --git a/resources/js/components/map/Viewer.jsx b/resources/js/components/map/Viewer.jsx
new file mode 100644 (file)
index 0000000..473c179
--- /dev/null
@@ -0,0 +1,109 @@
+import OpenSeadragon from 'openseadragon';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const Viewer = () => {
+       const [viewer, setViewer] = React.useState(null);
+
+       const container = React.useRef();
+       const { t } = useTranslation();
+
+       React.useEffect(() => {
+               if (!container.current) return;
+
+               const v = OpenSeadragon({
+                       element: container.current,
+                       preserveViewport: true,
+                       sequenceMode: true,
+                       showNavigator: true,
+                       showNavigationControl: false,
+                       showSequenceControl: false,
+                       //tileSources: [
+                       //      new OpenSeadragon.DziTileSource({
+                       //              width: 8192,
+                       //              height: 8192,
+                       //              tileSize: 256,
+                       //              tileOverlap: 0,
+                       //              minLevel: 8,
+                       //              maxLevel: 13,
+                       //              tilesUrl: '/media/alttp/map/lw_files/',
+                       //              fileFormat: 'png',
+                       //      }), new OpenSeadragon.DziTileSource({
+                       //              width: 8192,
+                       //              height: 8192,
+                       //              tileSize: 256,
+                       //              tileOverlap: 0,
+                       //              minLevel: 8,
+                       //              maxLevel: 13,
+                       //              tilesUrl: '/media/alttp/map/dw_files/',
+                       //              fileFormat: 'png',
+                       //      }), new OpenSeadragon.DziTileSource({
+                       //              width: 8192,
+                       //              height: 8192,
+                       //              tileSize: 256,
+                       //              tileOverlap: 0,
+                       //              minLevel: 8,
+                       //              maxLevel: 13,
+                       //              tilesUrl: '/media/alttp/map/sp_files/',
+                       //              fileFormat: 'png',
+                       //      }), new OpenSeadragon.DziTileSource({
+                       //              width: 16384,
+                       //              height: 16384,
+                       //              tileSize: 256,
+                       //              tileOverlap: 0,
+                       //              minLevel: 8,
+                       //              maxLevel: 14,
+                       //              tilesUrl: '/media/alttp/map/uw_files/',
+                       //              fileFormat: 'png',
+                       //      }),
+                       //],
+               });
+               setViewer(v);
+               return () => {
+                       v.destroy();
+               };
+       }, [container.current]);
+
+       const goToPage = React.useCallback((p) => {
+               if (viewer) viewer.goToPage(p);
+       }, [viewer]);
+
+       return <>
+               <div className="d-flex align-items-center justify-content-between">
+                       <div className="button-bar">
+                               <Button
+                                       onClick={() => goToPage(0)}
+                                       title={t('map.lwLong')}
+                                       variant="outline-secondary"
+                               >
+                                       {t('map.lwShort')}
+                               </Button>
+                               <Button
+                                       onClick={() => goToPage(1)}
+                                       title={t('map.dwLong')}
+                                       variant="outline-secondary"
+                               >
+                                       {t('map.dwShort')}
+                               </Button>
+                               <Button
+                                       onClick={() => goToPage(2)}
+                                       title={t('map.spLong')}
+                                       variant="outline-secondary"
+                               >
+                                       {t('map.spShort')}
+                               </Button>
+                               <Button
+                                       onClick={() => goToPage(3)}
+                                       title={t('map.uwLong')}
+                                       variant="outline-secondary"
+                               >
+                                       {t('map.uwShort')}
+                               </Button>
+                       </div>
+               </div>
+               <div ref={container} style={{ height: '80vh' }} />
+       </>;
+};
+
+export default Viewer;
diff --git a/resources/js/components/participants/List.js b/resources/js/components/participants/List.js
deleted file mode 100644 (file)
index e210f65..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Col, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import Box from '../users/Box';
-import i18n from '../../i18n';
-
-const List = ({ participants }) => participants && participants.length ?
-       <Row className="participants">
-               {participants.map(participant =>
-                       <Col md={4} lg={3} key={participant.id}>
-                               <Box user={participant.user} />
-                       </Col>
-               )}
-       </Row>
-:
-       <Alert variant="info">
-               {i18n.t('participants.empty')}
-       </Alert>
-;
-
-List.propTypes = {
-       participants: PropTypes.arrayOf(PropTypes.shape({
-               id: PropTypes.number,
-               user: PropTypes.shape({
-                       discriminator: PropTypes.string,
-                       username: PropTypes.string,
-               }),
-       })),
-};
-
-export default withTranslation()(List);
diff --git a/resources/js/components/participants/List.jsx b/resources/js/components/participants/List.jsx
new file mode 100644 (file)
index 0000000..e210f65
--- /dev/null
@@ -0,0 +1,33 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Col, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import Box from '../users/Box';
+import i18n from '../../i18n';
+
+const List = ({ participants }) => participants && participants.length ?
+       <Row className="participants">
+               {participants.map(participant =>
+                       <Col md={4} lg={3} key={participant.id}>
+                               <Box user={participant.user} />
+                       </Col>
+               )}
+       </Row>
+:
+       <Alert variant="info">
+               {i18n.t('participants.empty')}
+       </Alert>
+;
+
+List.propTypes = {
+       participants: PropTypes.arrayOf(PropTypes.shape({
+               id: PropTypes.number,
+               user: PropTypes.shape({
+                       discriminator: PropTypes.string,
+                       username: PropTypes.string,
+               }),
+       })),
+};
+
+export default withTranslation()(List);
diff --git a/resources/js/components/protocol/Dialog.js b/resources/js/components/protocol/Dialog.js
deleted file mode 100644 (file)
index 1b66c6c..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Button, Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import List from './List';
-import i18n from '../../i18n';
-
-class Dialog extends React.Component {
-
-       componentDidMount() {
-               this.timer = setInterval(() => {
-                       this.forceUpdate();
-               }, 30000);
-       }
-
-       componentWillUnmount() {
-               clearInterval(this.timer);
-       }
-
-       render() {
-               const {
-                       onHide,
-                       protocol,
-                       show,
-               } = this.props;
-               return <Modal className="protocol-dialog" onHide={onHide} show={show} size="lg">
-                       <Modal.Header closeButton>
-                               <Modal.Title>
-                                       {i18n.t('protocol.heading')}
-                               </Modal.Title>
-                       </Modal.Header>
-                       {protocol && protocol.length ?
-                               <List protocol={protocol} />
-                       :
-                               <Modal.Body>
-                                       <Alert variant="info">
-                                               {i18n.t('protocol.empty')}
-                                       </Alert>
-                               </Modal.Body>
-                       }
-                       <Modal.Footer>
-                               <Button onClick={onHide} variant="secondary">
-                                       {i18n.t('button.close')}
-                               </Button>
-                       </Modal.Footer>
-               </Modal>;
-       }
-
-}
-
-Dialog.propTypes = {
-       onHide: PropTypes.func,
-       protocol: PropTypes.arrayOf(PropTypes.shape({
-               type: PropTypes.string,
-       })),
-       show: PropTypes.bool,
-};
-
-Dialog.defaultProps = {
-       onHide: null,
-       protocol: null,
-       show: false,
-};
-
-export default withTranslation()(Dialog);
diff --git a/resources/js/components/protocol/Dialog.jsx b/resources/js/components/protocol/Dialog.jsx
new file mode 100644 (file)
index 0000000..dcf064b
--- /dev/null
@@ -0,0 +1,46 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import List from './List';
+
+const Dialog = ({
+       onHide = null,
+       protocol = null,
+       show = false,
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal className="protocol-dialog" onHide={onHide} show={show} size="lg">
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('protocol.heading')}
+                       </Modal.Title>
+               </Modal.Header>
+               {protocol && protocol.length ?
+                       <List protocol={protocol} />
+               :
+                       <Modal.Body>
+                               <Alert variant="info">
+                                       {t('protocol.empty')}
+                               </Alert>
+                       </Modal.Body>
+               }
+               <Modal.Footer>
+                       <Button onClick={onHide} variant="secondary">
+                               {t('button.close')}
+                       </Button>
+               </Modal.Footer>
+       </Modal>;
+};
+
+Dialog.propTypes = {
+       onHide: PropTypes.func,
+       protocol: PropTypes.arrayOf(PropTypes.shape({
+               type: PropTypes.string,
+       })),
+       show: PropTypes.bool,
+};
+
+export default Dialog;
diff --git a/resources/js/components/protocol/Item.js b/resources/js/components/protocol/Item.js
deleted file mode 100644 (file)
index 7dba2a3..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-import moment from 'moment';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { ListGroup } from 'react-bootstrap';
-import { Trans, withTranslation } from 'react-i18next';
-
-import Icon from '../common/Icon';
-import Spoiler from '../common/Spoiler';
-import { formatTime } from '../../helpers/Result';
-import { getUserName } from '../../helpers/User';
-import i18n from '../../i18n';
-
-const getEntryDate = entry => {
-       const dateStr = moment(entry.created_at).fromNow();
-       return entry.user
-               ? `${entry.user.username} ${dateStr}`
-               : dateStr;
-};
-
-const getEntryDetailsUsername = entry => {
-       if (!entry || !entry.details || !entry.details.user) return 'Anonymous';
-       return getUserName(entry.details.user);
-};
-
-const getEntryRoundNumber = entry =>
-       (entry && entry.details && entry.details.round && entry.details.round.number) || '?';
-
-const getEntryResultComment = entry => {
-       if (!entry || !entry.details || !entry.details.result || !entry.details.result.comment) {
-               return '';
-       }
-       return entry.details.result.comment;
-};
-
-const getEntryResultTime = entry => {
-       if (!entry || !entry.details || !entry.details.result) return 'ERROR';
-       const result = entry.details.result;
-       if (result.forfeit) return 'DNF XX';
-       return formatTime(result);
-};
-
-const getEntryDescription = entry => {
-       switch (entry.type) {
-               case 'application.accepted':
-               case 'application.received':
-               case 'application.rejected':
-                       return i18n.t(
-                               `protocol.description.${entry.type}`,
-                               {
-                                       ...entry,
-                                       username: getEntryDetailsUsername(entry),
-                               },
-                       );
-               case 'result.comment': {
-                       const comment = getEntryResultComment(entry);
-                       const number = getEntryRoundNumber(entry);
-                       return <Trans i18nKey={`protocol.description.${entry.type}`}>
-                               {{number}}
-                               <Spoiler>{{comment}}</Spoiler>,
-                       </Trans>;
-               }
-               case 'result.report': {
-                       const number = getEntryRoundNumber(entry);
-                       const time = getEntryResultTime(entry);
-                       return <Trans i18nKey={`protocol.description.${entry.type}`}>
-                               {{number}}
-                               <Spoiler>{{time}}</Spoiler>,
-                       </Trans>;
-               }
-               case 'round.create':
-               case 'round.edit':
-               case 'round.lock':
-               case 'round.seed':
-               case 'round.unlock':
-                       return i18n.t(
-                               `protocol.description.${entry.type}`,
-                               {
-                                       ...entry,
-                                       number: getEntryRoundNumber(entry),
-                               },
-                       );
-               case 'tournament.close':
-               case 'tournament.discord':
-               case 'tournament.lock':
-               case 'tournament.open':
-               case 'tournament.settings':
-               case 'tournament.unlock':
-                       return i18n.t(
-                               `protocol.description.${entry.type}`,
-                               entry,
-                       );
-               default:
-                       return i18n.t('protocol.description.unknown', entry);
-       }
-};
-
-const getEntryIcon = entry => {
-       switch (entry.type) {
-               case 'result.report':
-                       return <Icon.RESULT />;
-               case 'round.create':
-                       return <Icon.ADD />;
-               case 'round.lock':
-               case 'tournament.close':
-               case 'tournament.lock':
-                       return <Icon.LOCKED />;
-               case 'round.unlock':
-               case 'tournament.open':
-               case 'tournament.unlock':
-                       return <Icon.UNLOCKED />;
-               case 'tournament.discord':
-                       return <Icon.DISCORD />;
-               default:
-                       return <Icon.PROTOCOL />;
-       }
-};
-
-const Item = ({ entry }) =>
-       <ListGroup.Item className="d-flex align-items-center">
-               <div className="pe-3 text-muted">
-                       {getEntryIcon(entry)}
-               </div>
-               <div>
-                       <div>
-                               {getEntryDescription(entry)}
-                       </div>
-                       <div
-                               className="text-muted"
-                               title={moment(entry.created_at).format('LLLL')}
-                       >
-                               {getEntryDate(entry)}
-                       </div>
-               </div>
-       </ListGroup.Item>;
-
-Item.propTypes = {
-       entry: PropTypes.shape({
-               created_at: PropTypes.string,
-       }),
-};
-
-Item.defaultProps = {
-       entry: {},
-};
-
-export default withTranslation()(Item);
diff --git a/resources/js/components/protocol/Item.jsx b/resources/js/components/protocol/Item.jsx
new file mode 100644 (file)
index 0000000..17dd744
--- /dev/null
@@ -0,0 +1,161 @@
+import moment from 'moment';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { ListGroup } from 'react-bootstrap';
+import { Trans, useTranslation } from 'react-i18next';
+
+import Icon from '../common/Icon';
+import Spoiler from '../common/Spoiler';
+import { formatTime } from '../../helpers/Result';
+import { getUserName } from '../../helpers/User';
+
+const getEntryDate = entry => {
+       const dateStr = moment(entry.created_at).fromNow();
+       return entry.user
+               ? `${entry.user.username} ${dateStr}`
+               : dateStr;
+};
+
+const getEntryDetailsUsername = entry => {
+       if (!entry || !entry.details || !entry.details.user) return 'Anonymous';
+       return getUserName(entry.details.user);
+};
+
+const getEntryRoundNumber = entry =>
+       (entry && entry.details && entry.details.round && entry.details.round.number) || '?';
+
+const getEntryResultComment = entry => {
+       if (!entry || !entry.details || !entry.details.result || !entry.details.result.comment) {
+               return '';
+       }
+       return entry.details.result.comment;
+};
+
+const getEntryResultTime = entry => {
+       if (!entry || !entry.details || !entry.details.result) return 'ERROR';
+       const result = entry.details.result;
+       if (result.forfeit) return 'DNF XX';
+       return formatTime(result);
+};
+
+const getEntryDescription = (entry, t) => {
+       switch (entry.type) {
+               case 'application.accepted':
+               case 'application.received':
+               case 'application.rejected':
+                       return t(
+                               `protocol.description.${entry.type}`,
+                               {
+                                       ...entry,
+                                       username: getEntryDetailsUsername(entry),
+                               },
+                       );
+               case 'result.comment': {
+                       const comment = getEntryResultComment(entry);
+                       const number = getEntryRoundNumber(entry);
+                       return <Trans i18nKey={`protocol.description.${entry.type}`}>
+                               {{number}}
+                               <Spoiler>{{comment}}</Spoiler>,
+                       </Trans>;
+               }
+               case 'result.report': {
+                       const number = getEntryRoundNumber(entry);
+                       const time = getEntryResultTime(entry);
+                       return <Trans i18nKey={`protocol.description.${entry.type}`}>
+                               {{number}}
+                               <Spoiler>{{time}}</Spoiler>,
+                       </Trans>;
+               }
+               case 'round.create':
+               case 'round.delete':
+               case 'round.edit':
+               case 'round.lock':
+               case 'round.seed':
+               case 'round.unlock':
+                       return t(
+                               `protocol.description.${entry.type}`,
+                               {
+                                       ...entry,
+                                       number: getEntryRoundNumber(entry),
+                               },
+                       );
+               case 'tournament.close':
+               case 'tournament.discord':
+               case 'tournament.lock':
+               case 'tournament.open':
+               case 'tournament.settings':
+               case 'tournament.unlock':
+                       return t(
+                               `protocol.description.${entry.type}`,
+                               entry,
+                       );
+               default:
+                       return t('protocol.description.unknown', entry);
+       }
+};
+
+const getEntryIcon = entry => {
+       switch (entry.type) {
+               case 'result.report':
+                       return <Icon.RESULT />;
+               case 'round.create':
+                       return <Icon.ADD />;
+               case 'round.delete':
+                       return <Icon.REMOVE />;
+               case 'round.lock':
+               case 'tournament.close':
+               case 'tournament.lock':
+                       return <Icon.LOCKED />;
+               case 'round.unlock':
+               case 'tournament.open':
+               case 'tournament.unlock':
+                       return <Icon.UNLOCKED />;
+               case 'tournament.discord':
+                       return <Icon.DISCORD />;
+               default:
+                       return <Icon.PROTOCOL />;
+       }
+};
+
+const Item = ({ entry = {} }) => {
+       const { t } = useTranslation();
+
+       const icon = React.useMemo(() => getEntryIcon(entry), [entry]);
+       const description = React.useMemo(() => getEntryDescription(entry, t), [entry, t]);
+       const [date, setDate] = React.useState(getEntryDate(entry));
+
+       React.useEffect(() => {
+               setDate(getEntryDate(entry));
+               const timer = setInterval(() => {
+                       setDate(getEntryDate(entry));
+               }, 30_000);
+               return () => {
+                       clearInterval(timer);
+               };
+       }, [entry]);
+
+       return <ListGroup.Item className="d-flex align-items-center">
+               <div className="pe-3 text-muted">
+                       {icon}
+               </div>
+               <div>
+                       <div>
+                               {description}
+                       </div>
+                       <div
+                               className="text-muted"
+                               title={moment(entry.created_at).format('LLLL')}
+                       >
+                               {date}
+                       </div>
+               </div>
+       </ListGroup.Item>;
+};
+
+Item.propTypes = {
+       entry: PropTypes.shape({
+               created_at: PropTypes.string,
+       }),
+};
+
+export default Item;
diff --git a/resources/js/components/protocol/List.js b/resources/js/components/protocol/List.js
deleted file mode 100644 (file)
index 55e0ecb..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { ListGroup } from 'react-bootstrap';
-
-import Item from './Item';
-
-const List = ({ protocol }) =>
-       <ListGroup variant="flush">
-               {protocol ? protocol.map(entry =>
-                       <Item key={entry.id} entry={entry} />
-               ) : null}
-       </ListGroup>;
-
-List.propTypes = {
-       protocol: PropTypes.arrayOf(PropTypes.shape({
-       })),
-};
-
-List.defaultProps = {
-       protocol: [],
-};
-
-export default List;
diff --git a/resources/js/components/protocol/List.jsx b/resources/js/components/protocol/List.jsx
new file mode 100644 (file)
index 0000000..9179ad5
--- /dev/null
@@ -0,0 +1,19 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { ListGroup } from 'react-bootstrap';
+
+import Item from './Item';
+
+const List = ({ protocol = [] }) =>
+       <ListGroup variant="flush">
+               {protocol ? protocol.map(entry =>
+                       <Item key={entry.id} entry={entry} />
+               ) : null}
+       </ListGroup>;
+
+List.propTypes = {
+       protocol: PropTypes.arrayOf(PropTypes.shape({
+       })),
+};
+
+export default List;
diff --git a/resources/js/components/protocol/Protocol.js b/resources/js/components/protocol/Protocol.js
deleted file mode 100644 (file)
index a2bb930..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React, { useEffect, useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import Dialog from './Dialog';
-import Icon from '../common/Icon';
-import i18n from '../../i18n';
-
-const Protocol = ({ id }) => {
-       const [showDialog, setShowDialog] = useState(false);
-       const [protocol, setProtocol] = useState([]);
-
-       useEffect(() => {
-               const ctrl = new AbortController();
-               axios
-                       .get(`/api/protocol/${id}`, { signal: ctrl.signal })
-                       .then(response => {
-                               setProtocol(response.data);
-                       });
-               return () => {
-                       ctrl.abort();
-               };
-       }, [id]);
-
-       useEffect(() => {
-               window.Echo.private(`Protocol.${id}`)
-                       .listen('ProtocolAdded', e => {
-                               if (e.protocol) {
-                                       setProtocol(protocol => [e.protocol, ...protocol]);
-                               }
-                       });
-               return () => {
-                       window.Echo.leave(`Protocol.${id}`);
-               };
-       }, [id]);
-
-       return (
-               <>
-                       <Button
-                               onClick={() => setShowDialog(true)}
-                               title={i18n.t('button.protocol')}
-                               variant="outline-info"
-                       >
-                               <Icon.PROTOCOL title="" />
-                       </Button>
-                       <Dialog
-                               onHide={() => setShowDialog(false)}
-                               protocol={protocol}
-                               show={showDialog}
-                       />
-               </>
-       );
-};
-
-Protocol.propTypes = {
-       id: PropTypes.number,
-};
-
-export default withTranslation()(Protocol);
diff --git a/resources/js/components/protocol/Protocol.jsx b/resources/js/components/protocol/Protocol.jsx
new file mode 100644 (file)
index 0000000..4b832c7
--- /dev/null
@@ -0,0 +1,62 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React, { useEffect, useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Dialog from './Dialog';
+import Icon from '../common/Icon';
+
+const Protocol = ({ id }) => {
+       const [showDialog, setShowDialog] = useState(false);
+       const [protocol, setProtocol] = useState([]);
+
+       const { t } = useTranslation();
+
+       useEffect(() => {
+               const ctrl = new AbortController();
+               axios
+                       .get(`/api/protocol/${id}`, { signal: ctrl.signal })
+                       .then(response => {
+                               setProtocol(response.data);
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [id]);
+
+       useEffect(() => {
+               window.Echo.private(`Protocol.${id}`)
+                       .listen('ProtocolAdded', e => {
+                               if (e.protocol) {
+                                       setProtocol(protocol => [e.protocol, ...protocol]);
+                               }
+                       });
+               return () => {
+                       window.Echo.leave(`Protocol.${id}`);
+               };
+       }, [id]);
+
+       return (
+               <>
+                       <Button
+                               onClick={() => setShowDialog(true)}
+                               title={t('button.protocol')}
+                               variant="outline-info"
+                       >
+                               <Icon.PROTOCOL title="" />
+                       </Button>
+                       <Dialog
+                               onHide={() => setShowDialog(false)}
+                               protocol={protocol}
+                               show={showDialog}
+                       />
+               </>
+       );
+};
+
+Protocol.propTypes = {
+       id: PropTypes.number,
+};
+
+export default Protocol;
diff --git a/resources/js/components/protocol/RoundProtocol.jsx b/resources/js/components/protocol/RoundProtocol.jsx
new file mode 100644 (file)
index 0000000..8f7648c
--- /dev/null
@@ -0,0 +1,53 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React, { useEffect, useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Dialog from './Dialog';
+import Icon from '../common/Icon';
+
+const RoundProtocol = ({ roundId, tournamentId }) => {
+       const [showDialog, setShowDialog] = useState(false);
+       const [protocol, setProtocol] = useState([]);
+
+       const { t } = useTranslation();
+
+       useEffect(() => {
+               if (!showDialog) return;
+               const ctrl = new AbortController();
+               axios
+                       .get(`/api/protocol/${tournamentId}/${roundId}`, { signal: ctrl.signal })
+                       .then(response => {
+                               setProtocol(response.data);
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [roundId, showDialog, tournamentId]);
+
+       return (
+               <>
+                       <Button
+                               onClick={() => setShowDialog(true)}
+                               size="sm"
+                               title={t('button.protocol')}
+                               variant="outline-info"
+                       >
+                               <Icon.PROTOCOL title="" />
+                       </Button>
+                       <Dialog
+                               onHide={() => setShowDialog(false)}
+                               protocol={protocol}
+                               show={showDialog}
+                       />
+               </>
+       );
+};
+
+RoundProtocol.propTypes = {
+       roundId: PropTypes.number,
+       tournamentId: PropTypes.number,
+};
+
+export default RoundProtocol;
diff --git a/resources/js/components/results/DetailDialog.js b/resources/js/components/results/DetailDialog.js
deleted file mode 100644 (file)
index 5739bbf..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Box from '../users/Box';
-import { getTime } from '../../helpers/Result';
-import { maySeeResults } from '../../helpers/permissions';
-import { findResult } from '../../helpers/User';
-import { useUser } from '../../hooks/user';
-
-const getPlacement = (result, t) =>
-       `${result.placement}. (${t('results.points', { count: result.score })})`;
-
-const DetailDialog = ({
-       onHide,
-       round,
-       show,
-       tournament,
-       user,
-}) => {
-       const { t } = useTranslation();
-       const { user: authUser } = useUser();
-
-       const result = React.useMemo(
-               () => findResult(user, round),
-               [round, user],
-       );
-       const maySee = React.useMemo(
-               () => maySeeResults(authUser, tournament, round),
-               [authUser, round, tournament],
-       );
-
-       return <Modal className="result-dialog" onHide={onHide} show={show}>
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {t('results.details')}
-                       </Modal.Title>
-               </Modal.Header>
-               <Modal.Body>
-                       <Row>
-                               <Form.Group as={Col} sm={6}>
-                                       <Form.Label>{t('results.round')}</Form.Label>
-                                       <div>
-                                               #{round.number || '?'}
-                                               {' '}
-                                               {t('rounds.date', { date: new Date(round.created_at) })}
-                                       </div>
-                               </Form.Group>
-                               <Form.Group as={Col} sm={6}>
-                                       <Form.Label>{t('results.runner')}</Form.Label>
-                                       <div><Box user={user} /></div>
-                               </Form.Group>
-                               <Form.Group as={Col} sm={6}>
-                                       <Form.Label>{t('results.result')}</Form.Label>
-                                       <div>
-                                               {maySee && result && result.has_finished
-                                                       ? getTime(result, maySee)
-                                                       : t('results.pending')}
-                                       </div>
-                               </Form.Group>
-                               <Form.Group as={Col} sm={6}>
-                                       <Form.Label>{t('results.placement')}</Form.Label>
-                                       <div>
-                                               {maySee && result && result.placement
-                                                       ? getPlacement(result, t)
-                                                       : t('results.pending')}
-                                       </div>
-                               </Form.Group>
-                               {maySee && result && result.comment ?
-                                       <Form.Group as={Col} sm={12}>
-                                               <Form.Label>{t('results.comment')}</Form.Label>
-                                               <div>{result.comment}</div>
-                                       </Form.Group>
-                               : null}
-                       </Row>
-               </Modal.Body>
-               <Modal.Footer>
-                       <Button onClick={onHide} variant="secondary">
-                               {t('button.close')}
-                       </Button>
-               </Modal.Footer>
-       </Modal>;
-};
-
-DetailDialog.propTypes = {
-       onHide: PropTypes.func,
-       round: PropTypes.shape({
-               created_at: PropTypes.string,
-               number: PropTypes.number,
-       }),
-       show: PropTypes.bool,
-       tournament: PropTypes.shape({
-       }),
-       user: PropTypes.shape({
-       }),
-};
-
-export default DetailDialog;
diff --git a/resources/js/components/results/DetailDialog.jsx b/resources/js/components/results/DetailDialog.jsx
new file mode 100644 (file)
index 0000000..60e6b74
--- /dev/null
@@ -0,0 +1,99 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Box from '../users/Box';
+import { getTime } from '../../helpers/Result';
+import { maySeeResult } from '../../helpers/permissions';
+import { findResult } from '../../helpers/User';
+import { useUser } from '../../hooks/user';
+
+const getPlacement = (result, t) =>
+       `${result.placement}. (${t('results.points', { count: result.score })})`;
+
+const DetailDialog = ({
+       onHide,
+       round,
+       show,
+       tournament,
+       user,
+}) => {
+       const { t } = useTranslation();
+       const { user: authUser } = useUser();
+
+       const result = React.useMemo(
+               () => findResult(user, round),
+               [round, user],
+       );
+       const maySee = React.useMemo(
+               () => maySeeResult(authUser, tournament, round, result),
+               [authUser, result, round, tournament],
+       );
+
+       return <Modal className="result-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('results.details')}
+                       </Modal.Title>
+               </Modal.Header>
+               <Modal.Body>
+                       <Row>
+                               <Form.Group as={Col} sm={6}>
+                                       <Form.Label>{t('results.round')}</Form.Label>
+                                       <div>
+                                               #{round.number || '?'}
+                                               {' '}
+                                               {t('rounds.date', { date: new Date(round.created_at) })}
+                                       </div>
+                               </Form.Group>
+                               <Form.Group as={Col} sm={6}>
+                                       <Form.Label>{t('results.runner')}</Form.Label>
+                                       <div><Box user={user} /></div>
+                               </Form.Group>
+                               <Form.Group as={Col} sm={6}>
+                                       <Form.Label>{t('results.result')}</Form.Label>
+                                       <div>
+                                               {maySee && result && result.has_finished
+                                                       ? getTime(result, maySee)
+                                                       : t('results.pending')}
+                                       </div>
+                               </Form.Group>
+                               <Form.Group as={Col} sm={6}>
+                                       <Form.Label>{t('results.placement')}</Form.Label>
+                                       <div>
+                                               {maySee && result && result.placement
+                                                       ? getPlacement(result, t)
+                                                       : t('results.pending')}
+                                       </div>
+                               </Form.Group>
+                               {maySee && result && result.comment ?
+                                       <Form.Group as={Col} sm={12}>
+                                               <Form.Label>{t('results.comment')}</Form.Label>
+                                               <div>{result.comment}</div>
+                                       </Form.Group>
+                               : null}
+                       </Row>
+               </Modal.Body>
+               <Modal.Footer>
+                       <Button onClick={onHide} variant="secondary">
+                               {t('button.close')}
+                       </Button>
+               </Modal.Footer>
+       </Modal>;
+};
+
+DetailDialog.propTypes = {
+       onHide: PropTypes.func,
+       round: PropTypes.shape({
+               created_at: PropTypes.string,
+               number: PropTypes.number,
+       }),
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+       }),
+       user: PropTypes.shape({
+       }),
+};
+
+export default DetailDialog;
diff --git a/resources/js/components/results/Item.js b/resources/js/components/results/Item.js
deleted file mode 100644 (file)
index 2e29d75..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import DetailDialog from './DetailDialog';
-import Icon from '../common/Icon';
-import Box from '../users/Box';
-import { getIcon, getTime } from '../../helpers/Result';
-import { maySeeResults } from '../../helpers/permissions';
-import { findResult } from '../../helpers/User';
-import { useUser } from '../../hooks/user';
-
-const getClassName = result => {
-       const classNames = ['status'];
-       if (result && result.has_finished) {
-               classNames.push('finished');
-               if (result.comment) {
-                       classNames.push('has-comment');
-               }
-       } else {
-               classNames.push('pending');
-       }
-       return classNames.join(' ');
-};
-
-const twitchReg = /^https?:\/\/(www\.)?twitch\.tv/;
-const youtubeReg = /^https?:\/\/(www\.)?youtu(\.be|be\.)/;
-
-const getVoDVariant = result => {
-       if (!result || !result.vod) return 'outline-secondary';
-       if (twitchReg.test(result.vod)) {
-               return 'twitch';
-       }
-       if (youtubeReg.test(result.vod)) {
-               return 'outline-youtube';
-       }
-       return 'outline-secondary';
-};
-
-const getVoDIcon = result => {
-       const variant = getVoDVariant(result);
-       if (variant === 'twitch') {
-               return <Icon.TWITCH title="" />;
-       }
-       if (variant === 'outline-youtube') {
-               return <Icon.YOUTUBE title="" />;
-       }
-       return <Icon.VIDEO title="" />;
-};
-
-const Item = ({
-       round,
-       tournament,
-       user,
-}) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       const { t } = useTranslation();
-       const { user: authUser } = useUser();
-
-       const result = React.useMemo(
-               () => findResult(user, round),
-               [round, user],
-       );
-       const maySee = React.useMemo(
-               () => maySeeResults(authUser, tournament, round),
-               [authUser, round, tournament],
-       );
-
-       return <div className="result">
-               <Box user={user} />
-               <div className="d-flex align-items-center justify-content-between">
-                       <Button
-                               className={getClassName(result)}
-                               onClick={() => setShowDialog(true)}
-                               title={maySee && result && result.comment ? result.comment : null}
-                       >
-                               <span className="time">
-                                       {getTime(result, maySee)}
-                               </span>
-                               {getIcon(result, maySee)}
-                       </Button>
-                       {maySee && result && result.vod ?
-                               <Button
-                                       className="vod-link"
-                                       href={result.vod}
-                                       size="sm"
-                                       target="_blank"
-                                       title={t('results.vod')}
-                                       variant={getVoDVariant(result)}
-                               >
-                                       {getVoDIcon(result)}
-                               </Button>
-                       : null}
-               </div>
-               <DetailDialog
-                       onHide={() => setShowDialog(false)}
-                       round={round}
-                       show={showDialog}
-                       tournament={tournament}
-                       user={user}
-               />
-       </div>;
-};
-
-Item.propTypes = {
-       round: PropTypes.shape({
-       }),
-       tournament: PropTypes.shape({
-       }),
-       user: PropTypes.shape({
-       }),
-};
-
-export default Item;
diff --git a/resources/js/components/results/Item.jsx b/resources/js/components/results/Item.jsx
new file mode 100644 (file)
index 0000000..da0c99e
--- /dev/null
@@ -0,0 +1,116 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import DetailDialog from './DetailDialog';
+import Icon from '../common/Icon';
+import Box from '../users/Box';
+import { getIcon, getTime } from '../../helpers/Result';
+import { maySeeResult } from '../../helpers/permissions';
+import { findResult } from '../../helpers/User';
+import { useUser } from '../../hooks/user';
+
+const getClassName = result => {
+       const classNames = ['status'];
+       if (result && result.has_finished) {
+               classNames.push('finished');
+               if (result.comment) {
+                       classNames.push('has-comment');
+               }
+       } else {
+               classNames.push('pending');
+       }
+       return classNames.join(' ');
+};
+
+const twitchReg = /^https?:\/\/(www\.)?twitch\.tv/;
+const youtubeReg = /^https?:\/\/(www\.)?youtu(\.be|be\.)/;
+
+const getVoDVariant = result => {
+       if (!result || !result.vod) return 'outline-secondary';
+       if (twitchReg.test(result.vod)) {
+               return 'twitch';
+       }
+       if (youtubeReg.test(result.vod)) {
+               return 'outline-youtube';
+       }
+       return 'outline-secondary';
+};
+
+const getVoDIcon = result => {
+       const variant = getVoDVariant(result);
+       if (variant === 'twitch') {
+               return <Icon.TWITCH title="" />;
+       }
+       if (variant === 'outline-youtube') {
+               return <Icon.YOUTUBE title="" />;
+       }
+       return <Icon.VIDEO title="" />;
+};
+
+const Item = ({
+       round,
+       tournament,
+       user,
+}) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       const { t } = useTranslation();
+       const { user: authUser } = useUser();
+
+       const result = React.useMemo(
+               () => findResult(user, round),
+               [round, user],
+       );
+       const maySee = React.useMemo(
+               () => maySeeResult(authUser, tournament, round, result),
+               [authUser, result, round, tournament],
+       );
+
+       return <div className="result">
+               <Box user={user} />
+               <div className="d-flex align-items-center justify-content-between">
+                       <Button
+                               className={getClassName(result)}
+                               onClick={() => setShowDialog(true)}
+                               title={maySee && result && result.comment ? result.comment : null}
+                       >
+                               <span className="time">
+                                       {getTime(result, maySee)}
+                               </span>
+                               {getIcon(result, maySeeResult(authUser, tournament, round))}
+                       </Button>
+                       {maySee && result && result.vod ?
+                               <Button
+                                       className="vod-link"
+                                       href={result.vod}
+                                       size="sm"
+                                       target="_blank"
+                                       title={t('results.vod')}
+                                       variant={getVoDVariant(result)}
+                               >
+                                       {getVoDIcon(result)}
+                               </Button>
+                       : null}
+               </div>
+               <DetailDialog
+                       onHide={() => setShowDialog(false)}
+                       round={round}
+                       show={showDialog}
+                       tournament={tournament}
+                       user={user}
+               />
+       </div>;
+};
+
+Item.propTypes = {
+       round: PropTypes.shape({
+       }),
+       tournament: PropTypes.shape({
+       }),
+       user: PropTypes.shape({
+       }),
+};
+
+export default Item;
diff --git a/resources/js/components/results/List.js b/resources/js/components/results/List.js
deleted file mode 100644 (file)
index 911b6a5..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import Item from './Item';
-import { sortByFinished, sortByResult } from '../../helpers/Participant';
-import { maySeeResults } from '../../helpers/permissions';
-import { getRunners } from '../../helpers/Tournament';
-import { compareResult } from '../../helpers/Result';
-import { useUser } from '../../hooks/user';
-
-const List = ({ round, tournament }) => {
-       const { user } = useUser();
-
-       if (tournament.type === 'open-async') {
-               const results = maySeeResults(user, tournament, round)
-                       ? (round.results || []).sort(compareResult)
-                       : round.results || [];
-               return <div className="results d-flex flex-wrap">
-                       {results.map(result =>
-                               <Item
-                                       key={result.id}
-                                       round={round}
-                                       tournament={tournament}
-                                       user={result.user}
-                               />
-                       )}
-               </div>;
-       }
-       const runners = maySeeResults(user, tournament, round)
-               ? sortByResult(getRunners(tournament), round)
-               : sortByFinished(getRunners(tournament), round);
-       return <div className="results d-flex flex-wrap">
-               {runners.map(participant =>
-                       <Item
-                               key={participant.id}
-                               round={round}
-                               tournament={tournament}
-                               user={participant.user}
-                       />
-               )}
-       </div>;
-};
-
-List.propTypes = {
-       round: PropTypes.shape({
-               results: PropTypes.arrayOf(PropTypes.shape({
-               })),
-       }),
-       tournament: PropTypes.shape({
-               participants: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               type: PropTypes.string,
-               users: PropTypes.arrayOf(PropTypes.shape({
-               })),
-       }),
-};
-
-export default List;
diff --git a/resources/js/components/results/List.jsx b/resources/js/components/results/List.jsx
new file mode 100644 (file)
index 0000000..f26a131
--- /dev/null
@@ -0,0 +1,58 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import Item from './Item';
+import { sortByFinished, sortByResult } from '../../helpers/Participant';
+import { maySeeResults } from '../../helpers/permissions';
+import { getRunners } from '../../helpers/Tournament';
+import { sortByTime, sortByUsername } from '../../helpers/Result';
+import { useUser } from '../../hooks/user';
+
+const List = ({ round, tournament }) => {
+       const { user } = useUser();
+
+       if (tournament.type === 'open-async') {
+               const results = maySeeResults(user, tournament, round)
+                       ? sortByTime(round.results || [])
+                       : sortByUsername(round.results || []);
+               return <div className="results d-flex flex-wrap">
+                       {results.map(result =>
+                               <Item
+                                       key={result.id}
+                                       round={round}
+                                       tournament={tournament}
+                                       user={result.user}
+                               />
+                       )}
+               </div>;
+       }
+       const runners = maySeeResults(user, tournament, round)
+               ? sortByResult(getRunners(tournament), round)
+               : sortByFinished(getRunners(tournament), round);
+       return <div className="results d-flex flex-wrap">
+               {runners.map(participant =>
+                       <Item
+                               key={participant.id}
+                               round={round}
+                               tournament={tournament}
+                               user={participant.user}
+                       />
+               )}
+       </div>;
+};
+
+List.propTypes = {
+       round: PropTypes.shape({
+               results: PropTypes.arrayOf(PropTypes.shape({
+               })),
+       }),
+       tournament: PropTypes.shape({
+               participants: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               type: PropTypes.string,
+               users: PropTypes.arrayOf(PropTypes.shape({
+               })),
+       }),
+};
+
+export default List;
diff --git a/resources/js/components/results/ReportButton.js b/resources/js/components/results/ReportButton.js
deleted file mode 100644 (file)
index 9db944e..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import ReportDialog from './ReportDialog';
-import Icon from '../common/Icon';
-import { findResult } from '../../helpers/User';
-import i18n from '../../i18n';
-
-const getButtonLabel = (user, round) => {
-       const result = findResult(user, round);
-       if (round.locked) {
-               if (result && result.comment) {
-                       return i18n.t('results.editComment');
-               } else {
-                       return i18n.t('results.addComment');
-               }
-       } else {
-               if (result && (result.time || result.forfeit)) {
-                       return i18n.t('results.edit');
-               } else {
-                       return i18n.t('results.report');
-               }
-       }
-};
-
-const ReportButton = ({ round, user }) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       if (round.locked && !findResult(user, round)) {
-               return null;
-       }
-
-       return <>
-               <Button
-                       onClick={() => setShowDialog(true)}
-                       variant="secondary"
-               >
-                       {getButtonLabel(user, round)}
-                       {' '}
-                       <Icon.EDIT title="" />
-               </Button>
-               <ReportDialog
-                       onHide={() => setShowDialog(false)}
-                       round={round}
-                       show={showDialog}
-                       user={user}
-               />
-       </>;
-};
-
-ReportButton.propTypes = {
-       round: PropTypes.shape({
-               locked: PropTypes.bool,
-       }),
-       tournament: PropTypes.shape({
-       }),
-       user: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(ReportButton);
diff --git a/resources/js/components/results/ReportButton.jsx b/resources/js/components/results/ReportButton.jsx
new file mode 100644 (file)
index 0000000..9db944e
--- /dev/null
@@ -0,0 +1,63 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import ReportDialog from './ReportDialog';
+import Icon from '../common/Icon';
+import { findResult } from '../../helpers/User';
+import i18n from '../../i18n';
+
+const getButtonLabel = (user, round) => {
+       const result = findResult(user, round);
+       if (round.locked) {
+               if (result && result.comment) {
+                       return i18n.t('results.editComment');
+               } else {
+                       return i18n.t('results.addComment');
+               }
+       } else {
+               if (result && (result.time || result.forfeit)) {
+                       return i18n.t('results.edit');
+               } else {
+                       return i18n.t('results.report');
+               }
+       }
+};
+
+const ReportButton = ({ round, user }) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       if (round.locked && !findResult(user, round)) {
+               return null;
+       }
+
+       return <>
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       variant="secondary"
+               >
+                       {getButtonLabel(user, round)}
+                       {' '}
+                       <Icon.EDIT title="" />
+               </Button>
+               <ReportDialog
+                       onHide={() => setShowDialog(false)}
+                       round={round}
+                       show={showDialog}
+                       user={user}
+               />
+       </>;
+};
+
+ReportButton.propTypes = {
+       round: PropTypes.shape({
+               locked: PropTypes.bool,
+       }),
+       tournament: PropTypes.shape({
+       }),
+       user: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(ReportButton);
diff --git a/resources/js/components/results/ReportDialog.js b/resources/js/components/results/ReportDialog.js
deleted file mode 100644 (file)
index b3e5282..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import ReportForm from './ReportForm';
-import i18n from '../../i18n';
-
-const ReportDialog = ({
-       onHide,
-       round,
-       show,
-       user,
-}) =>
-<Modal className="report-dialog" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('results.report')}
-               </Modal.Title>
-       </Modal.Header>
-       <ReportForm
-               onCancel={onHide}
-               round={round}
-               user={user}
-       />
-</Modal>;
-
-ReportDialog.propTypes = {
-       onHide: PropTypes.func,
-       round: PropTypes.shape({
-       }),
-       show: PropTypes.bool,
-       tournament: PropTypes.shape({
-       }),
-       user: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(ReportDialog);
diff --git a/resources/js/components/results/ReportDialog.jsx b/resources/js/components/results/ReportDialog.jsx
new file mode 100644 (file)
index 0000000..b3e5282
--- /dev/null
@@ -0,0 +1,39 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import ReportForm from './ReportForm';
+import i18n from '../../i18n';
+
+const ReportDialog = ({
+       onHide,
+       round,
+       show,
+       user,
+}) =>
+<Modal className="report-dialog" onHide={onHide} show={show}>
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t('results.report')}
+               </Modal.Title>
+       </Modal.Header>
+       <ReportForm
+               onCancel={onHide}
+               round={round}
+               user={user}
+       />
+</Modal>;
+
+ReportDialog.propTypes = {
+       onHide: PropTypes.func,
+       round: PropTypes.shape({
+       }),
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+       }),
+       user: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(ReportDialog);
diff --git a/resources/js/components/results/ReportForm.js b/resources/js/components/results/ReportForm.js
deleted file mode 100644 (file)
index 2e85f4a..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-import axios from 'axios';
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import LargeCheck from '../common/LargeCheck';
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import { findResult } from '../../helpers/User';
-import { formatTime, parseTime } from '../../helpers/Result';
-import i18n from '../../i18n';
-import yup from '../../schema/yup';
-
-const ReportForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       round,
-       touched,
-       values,
-}) =>
-<Form noValidate onSubmit={handleSubmit}>
-       <Modal.Body>
-               {!round.locked ?
-                       <Row>
-                               <Form.Group as={Col} sm={9} controlId="report.time">
-                                       <Form.Label>{i18n.t('results.reportTime')}</Form.Label>
-                                       <Form.Control
-                                               isInvalid={!!(touched.time && errors.time)}
-                                               name="time"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               placeholder={values.forfeit ? 'DNF' : '1:22:59'}
-                                               type="text"
-                                               value={values.time || ''}
-                                       />
-                                       {touched.time && errors.time ?
-                                               <Form.Control.Feedback type="invalid">
-                                                       {i18n.t(errors.time)}
-                                               </Form.Control.Feedback>
-                                       :
-                                               <Form.Text muted>
-                                                       {parseTime(values.time) ?
-                                                               i18n.t(
-                                                                       'results.reportPreview',
-                                                                       { time: formatTime({ time: parseTime(values.time) })},
-                                                               )
-                                                       : null}
-                                               </Form.Text>
-                                       }
-                               </Form.Group>
-                               <Form.Group as={Col} sm={3} controlId="report.forfeit">
-                                       <Form.Label>{i18n.t('results.forfeit')}</Form.Label>
-                                       <Form.Control
-                                               as={LargeCheck}
-                                               isInvalid={!!(touched.forfeit && errors.forfeit)}
-                                               name="forfeit"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               value={!!values.forfeit}
-                                       />
-                               </Form.Group>
-                       </Row>
-               : null}
-               <Form.Group controlId="report.vod">
-                       <Form.Label>{i18n.t('results.vod')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.vod && errors.vod)}
-                               name="vod"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               placeholder="https://twitch.tv/youtube"
-                               type="text"
-                               value={values.vod || ''}
-                       />
-                       {touched.vod && errors.vod ?
-                               <Form.Control.Feedback type="invalid">
-                                       {i18n.t(errors.vod)}
-                               </Form.Control.Feedback>
-                       :
-                               <Form.Text muted>
-                                       {i18n.t('results.vodNote')}
-                               </Form.Text>
-                       }
-               </Form.Group>
-               <Form.Group controlId="report.comment">
-                       <Form.Label>{i18n.t('results.comment')}</Form.Label>
-                       <Form.Control
-                               as="textarea"
-                               isInvalid={!!(touched.comment && errors.comment)}
-                               name="comment"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               rows="6"
-                               value={values.comment || ''}
-                       />
-               </Form.Group>
-       </Modal.Body>
-       <Modal.Footer>
-               {onCancel ?
-                       <Button onClick={onCancel} variant="secondary">
-                               {i18n.t('button.cancel')}
-                       </Button>
-               : null}
-               <Button type="submit" variant="primary">
-                       {i18n.t('button.save')}
-               </Button>
-       </Modal.Footer>
-</Form>;
-
-ReportForm.propTypes = {
-       errors: PropTypes.shape({
-               comment: PropTypes.string,
-               forfeit: PropTypes.string,
-               time: PropTypes.string,
-               vod: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       round: PropTypes.shape({
-               locked: PropTypes.bool,
-       }),
-       touched: PropTypes.shape({
-               comment: PropTypes.bool,
-               forfeit: PropTypes.bool,
-               time: PropTypes.bool,
-               vod: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               comment: PropTypes.string,
-               forfeit: PropTypes.bool,
-               time: PropTypes.string,
-               vod: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'ReportForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { comment, forfeit, round_id, time, user_id, vod } = values;
-               const { setErrors } = actions;
-               const { onCancel } = actions.props;
-               try {
-                       await axios.post('/api/results', {
-                               comment,
-                               forfeit,
-                               round_id,
-                               time: parseTime(time) || 0,
-                               user_id,
-                               vod,
-                       });
-                       toastr.success(i18n.t('results.reportSuccess'));
-                       if (onCancel) {
-                               onCancel();
-                       }
-               } catch (e) {
-                       toastr.error(i18n.t('results.reportError'));
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ round, user }) => {
-               const result = findResult(user, round);
-               return {
-                       comment: result && result.comment ? result.comment : '',
-                       forfeit: result ? !!result.forfeit : false,
-                       round_id: round.id,
-                       time: result && result.time ? formatTime(result) : '',
-                       user_id: user.id,
-                       vod: result && result.vod ? result.vod : '',
-               };
-       },
-       validationSchema: yup.object().shape({
-               comment: yup.string(),
-               forfeit: yup.boolean().required(),
-               time: yup.string().time().when('forfeit', {
-                       is: false,
-                       then: () => yup.string().required().time(),
-               }),
-               vod: yup.string().url(),
-       }),
-})(withTranslation()(ReportForm));
diff --git a/resources/js/components/results/ReportForm.jsx b/resources/js/components/results/ReportForm.jsx
new file mode 100644 (file)
index 0000000..2e85f4a
--- /dev/null
@@ -0,0 +1,190 @@
+import axios from 'axios';
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import LargeCheck from '../common/LargeCheck';
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import { findResult } from '../../helpers/User';
+import { formatTime, parseTime } from '../../helpers/Result';
+import i18n from '../../i18n';
+import yup from '../../schema/yup';
+
+const ReportForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       round,
+       touched,
+       values,
+}) =>
+<Form noValidate onSubmit={handleSubmit}>
+       <Modal.Body>
+               {!round.locked ?
+                       <Row>
+                               <Form.Group as={Col} sm={9} controlId="report.time">
+                                       <Form.Label>{i18n.t('results.reportTime')}</Form.Label>
+                                       <Form.Control
+                                               isInvalid={!!(touched.time && errors.time)}
+                                               name="time"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               placeholder={values.forfeit ? 'DNF' : '1:22:59'}
+                                               type="text"
+                                               value={values.time || ''}
+                                       />
+                                       {touched.time && errors.time ?
+                                               <Form.Control.Feedback type="invalid">
+                                                       {i18n.t(errors.time)}
+                                               </Form.Control.Feedback>
+                                       :
+                                               <Form.Text muted>
+                                                       {parseTime(values.time) ?
+                                                               i18n.t(
+                                                                       'results.reportPreview',
+                                                                       { time: formatTime({ time: parseTime(values.time) })},
+                                                               )
+                                                       : null}
+                                               </Form.Text>
+                                       }
+                               </Form.Group>
+                               <Form.Group as={Col} sm={3} controlId="report.forfeit">
+                                       <Form.Label>{i18n.t('results.forfeit')}</Form.Label>
+                                       <Form.Control
+                                               as={LargeCheck}
+                                               isInvalid={!!(touched.forfeit && errors.forfeit)}
+                                               name="forfeit"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               value={!!values.forfeit}
+                                       />
+                               </Form.Group>
+                       </Row>
+               : null}
+               <Form.Group controlId="report.vod">
+                       <Form.Label>{i18n.t('results.vod')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.vod && errors.vod)}
+                               name="vod"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               placeholder="https://twitch.tv/youtube"
+                               type="text"
+                               value={values.vod || ''}
+                       />
+                       {touched.vod && errors.vod ?
+                               <Form.Control.Feedback type="invalid">
+                                       {i18n.t(errors.vod)}
+                               </Form.Control.Feedback>
+                       :
+                               <Form.Text muted>
+                                       {i18n.t('results.vodNote')}
+                               </Form.Text>
+                       }
+               </Form.Group>
+               <Form.Group controlId="report.comment">
+                       <Form.Label>{i18n.t('results.comment')}</Form.Label>
+                       <Form.Control
+                               as="textarea"
+                               isInvalid={!!(touched.comment && errors.comment)}
+                               name="comment"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               rows="6"
+                               value={values.comment || ''}
+                       />
+               </Form.Group>
+       </Modal.Body>
+       <Modal.Footer>
+               {onCancel ?
+                       <Button onClick={onCancel} variant="secondary">
+                               {i18n.t('button.cancel')}
+                       </Button>
+               : null}
+               <Button type="submit" variant="primary">
+                       {i18n.t('button.save')}
+               </Button>
+       </Modal.Footer>
+</Form>;
+
+ReportForm.propTypes = {
+       errors: PropTypes.shape({
+               comment: PropTypes.string,
+               forfeit: PropTypes.string,
+               time: PropTypes.string,
+               vod: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       round: PropTypes.shape({
+               locked: PropTypes.bool,
+       }),
+       touched: PropTypes.shape({
+               comment: PropTypes.bool,
+               forfeit: PropTypes.bool,
+               time: PropTypes.bool,
+               vod: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               comment: PropTypes.string,
+               forfeit: PropTypes.bool,
+               time: PropTypes.string,
+               vod: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'ReportForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { comment, forfeit, round_id, time, user_id, vod } = values;
+               const { setErrors } = actions;
+               const { onCancel } = actions.props;
+               try {
+                       await axios.post('/api/results', {
+                               comment,
+                               forfeit,
+                               round_id,
+                               time: parseTime(time) || 0,
+                               user_id,
+                               vod,
+                       });
+                       toastr.success(i18n.t('results.reportSuccess'));
+                       if (onCancel) {
+                               onCancel();
+                       }
+               } catch (e) {
+                       toastr.error(i18n.t('results.reportError'));
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ round, user }) => {
+               const result = findResult(user, round);
+               return {
+                       comment: result && result.comment ? result.comment : '',
+                       forfeit: result ? !!result.forfeit : false,
+                       round_id: round.id,
+                       time: result && result.time ? formatTime(result) : '',
+                       user_id: user.id,
+                       vod: result && result.vod ? result.vod : '',
+               };
+       },
+       validationSchema: yup.object().shape({
+               comment: yup.string(),
+               forfeit: yup.boolean().required(),
+               time: yup.string().time().when('forfeit', {
+                       is: false,
+                       then: () => yup.string().required().time(),
+               }),
+               vod: yup.string().url(),
+       }),
+})(withTranslation()(ReportForm));
diff --git a/resources/js/components/rounds/DeleteButton.jsx b/resources/js/components/rounds/DeleteButton.jsx
new file mode 100644 (file)
index 0000000..578380d
--- /dev/null
@@ -0,0 +1,43 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import DeleteDialog from './DeleteDialog';
+import Icon from '../common/Icon';
+
+const DeleteButton = ({
+       round,
+       tournament,
+}) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       const { t } = useTranslation();
+
+       return <>
+               <DeleteDialog
+                       onHide={() => setShowDialog(false)}
+                       round={round}
+                       show={showDialog}
+                       tournament={tournament}
+               />
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       size="sm"
+                       title={t('rounds.delete')}
+                       variant="outline-danger"
+               >
+                       <Icon.REMOVE title="" />
+               </Button>
+       </>;
+};
+
+DeleteButton.propTypes = {
+       round: PropTypes.shape({
+               locked: PropTypes.bool,
+       }),
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default DeleteButton;
diff --git a/resources/js/components/rounds/DeleteDialog.jsx b/resources/js/components/rounds/DeleteDialog.jsx
new file mode 100644 (file)
index 0000000..188f082
--- /dev/null
@@ -0,0 +1,60 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+const EditDialog = ({
+       onHide,
+       round,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       const handleDelete = React.useCallback(async() => {
+               try {
+                       await axios.delete(`/api/rounds/${round.id}`);
+                       onHide();
+               } catch (e) {
+                       toastr.error(t('rounds.deleteError'));
+               }
+       }, [onHide, round, t]);
+
+       return <Modal className="edit-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('rounds.delete')}
+                       </Modal.Title>
+               </Modal.Header>
+               <Modal.Body>
+                       <Alert variant="danger">
+                               {t('rounds.deleteConfirmMessage', {
+                                       ...round,
+                                       date: new Date(round.created_at),
+                               })}
+                       </Alert>
+               </Modal.Body>
+               <Modal.Footer>
+                       <Button onClick={onHide} variant="secondary">
+                               {t('button.cancel')}
+                       </Button>
+                       <Button onClick={handleDelete} variant="danger">
+                               {t('button.delete')}
+                       </Button>
+               </Modal.Footer>
+       </Modal>;
+};
+
+EditDialog.propTypes = {
+       onHide: PropTypes.func,
+       round: PropTypes.shape({
+               created_at: PropTypes.string,
+               id: PropTypes.number,
+       }),
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default EditDialog;
diff --git a/resources/js/components/rounds/EditButton.js b/resources/js/components/rounds/EditButton.js
deleted file mode 100644 (file)
index edc6fbf..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import EditDialog from './EditDialog';
-import Icon from '../common/Icon';
-import i18n from '../../i18n';
-
-const EditButton = ({
-       round,
-       tournament,
-}) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       return <>
-               <EditDialog
-                       onHide={() => setShowDialog(false)}
-                       round={round}
-                       show={showDialog}
-                       tournament={tournament}
-               />
-               <Button
-                       onClick={() => setShowDialog(true)}
-                       size="sm"
-                       title={i18n.t('rounds.edit')}
-                       variant="outline-secondary"
-               >
-                       <Icon.EDIT title="" />
-               </Button>
-       </>;
-};
-
-EditButton.propTypes = {
-       round: PropTypes.shape({
-               locked: PropTypes.bool,
-       }),
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(EditButton);
diff --git a/resources/js/components/rounds/EditButton.jsx b/resources/js/components/rounds/EditButton.jsx
new file mode 100644 (file)
index 0000000..d32b843
--- /dev/null
@@ -0,0 +1,43 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import EditDialog from './EditDialog';
+import Icon from '../common/Icon';
+
+const EditButton = ({
+       round,
+       tournament,
+}) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       const { t } = useTranslation();
+
+       return <>
+               <EditDialog
+                       onHide={() => setShowDialog(false)}
+                       round={round}
+                       show={showDialog}
+                       tournament={tournament}
+               />
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       size="sm"
+                       title={t('rounds.edit')}
+                       variant="outline-secondary"
+               >
+                       <Icon.EDIT title="" />
+               </Button>
+       </>;
+};
+
+EditButton.propTypes = {
+       round: PropTypes.shape({
+               locked: PropTypes.bool,
+       }),
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default EditButton;
diff --git a/resources/js/components/rounds/EditDialog.js b/resources/js/components/rounds/EditDialog.js
deleted file mode 100644 (file)
index 912a420..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import EditForm from './EditForm';
-import i18n from '../../i18n';
-
-const EditDialog = ({
-       onHide,
-       round,
-       show,
-}) =>
-<Modal className="edit-dialog" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('rounds.edit')}
-               </Modal.Title>
-       </Modal.Header>
-       <EditForm
-               onCancel={onHide}
-               round={round}
-       />
-</Modal>;
-
-EditDialog.propTypes = {
-       onHide: PropTypes.func,
-       round: PropTypes.shape({
-       }),
-       show: PropTypes.bool,
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(EditDialog);
diff --git a/resources/js/components/rounds/EditDialog.jsx b/resources/js/components/rounds/EditDialog.jsx
new file mode 100644 (file)
index 0000000..bf72c32
--- /dev/null
@@ -0,0 +1,37 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import EditForm from './EditForm';
+
+const EditDialog = ({
+       onHide,
+       round,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal className="edit-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('rounds.edit')}
+                       </Modal.Title>
+               </Modal.Header>
+               <EditForm
+                       onCancel={onHide}
+                       round={round}
+               />
+       </Modal>;
+};
+
+EditDialog.propTypes = {
+       onHide: PropTypes.func,
+       round: PropTypes.shape({
+       }),
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default EditDialog;
diff --git a/resources/js/components/rounds/EditForm.js b/resources/js/components/rounds/EditForm.js
deleted file mode 100644 (file)
index ac2cd42..0000000
+++ /dev/null
@@ -1,195 +0,0 @@
-import axios from 'axios';
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import SeedCodeInput from './SeedCodeInput';
-import UserSelect from '../common/UserSelect';
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import i18n from '../../i18n';
-import yup from '../../schema/yup';
-
-const EditForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       touched,
-       values,
-}) =>
-<Form noValidate onSubmit={handleSubmit}>
-       <Modal.Body>
-               <Row>
-                       <Form.Group as={Col} controlId="round.title">
-                               <Form.Label>{i18n.t('rounds.title')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.title && errors.title)}
-                                       name="title"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="text"
-                                       value={values.title || ''}
-                               />
-                               {touched.title && errors.title ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {i18n.t(errors.title)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-               <Row>
-                       <Form.Group as={Col} controlId="round.seed">
-                               <Form.Label>{i18n.t('rounds.seed')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.seed && errors.seed)}
-                                       name="seed"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="text"
-                                       value={values.seed || ''}
-                               />
-                               {touched.seed && errors.seed ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {i18n.t(errors.seed)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-               <Row>
-                       <Form.Group as={Col} controlId="round.spoiler">
-                               <Form.Label>{i18n.t('rounds.spoiler')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.spoiler && errors.spoiler)}
-                                       name="spoiler"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="text"
-                                       value={values.spoiler || ''}
-                               />
-                               {touched.spoiler && errors.spoiler ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {i18n.t(errors.spoiler)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-               <Row>
-                       <Form.Group as={Col}>
-                               <Form.Label>{i18n.t('rounds.code')}</Form.Label>
-                               <Form.Control
-                                       as={SeedCodeInput}
-                                       game={values.game || 'mixed'}
-                                       isInvalid={!!(touched.code && errors.code)}
-                                       name="code"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.code || []}
-                               />
-                               {touched.code && errors.code ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {i18n.t(errors.code)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-               <Row>
-                       <Form.Group as={Col}>
-                               <Form.Label>{i18n.t('rounds.rolled_by')}</Form.Label>
-                               <Form.Control
-                                       as={UserSelect}
-                                       isInvalid={!!(touched.rolled_by && errors.rolled_by)}
-                                       name="rolled_by"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.rolled_by || null}
-                               />
-                               {touched.rolled_by && errors.rolled_by ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {i18n.t(errors.rolled_by)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-       </Modal.Body>
-       <Modal.Footer>
-               {onCancel ?
-                       <Button onClick={onCancel} variant="secondary">
-                               {i18n.t('button.cancel')}
-                       </Button>
-               : null}
-               <Button type="submit" variant="primary">
-                       {i18n.t('button.save')}
-               </Button>
-       </Modal.Footer>
-</Form>;
-
-EditForm.propTypes = {
-       errors: PropTypes.shape({
-               code: PropTypes.arrayOf(PropTypes.string),
-               rolled_by: PropTypes.string,
-               seed: PropTypes.string,
-               spoiler: PropTypes.string,
-               title: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               code: PropTypes.arrayOf(PropTypes.bool),
-               rolled_by: PropTypes.bool,
-               seed: PropTypes.bool,
-               spoiler: PropTypes.bool,
-               title: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               code: PropTypes.arrayOf(PropTypes.string),
-               game: PropTypes.string,
-               rolled_by: PropTypes.string,
-               seed: PropTypes.string,
-               spoiler: PropTypes.string,
-               title: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'EditForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { round_id } = values;
-               const { setErrors } = actions;
-               const { onCancel } = actions.props;
-               try {
-                       await axios.put(`/api/rounds/${round_id}`, values);
-                       toastr.success(i18n.t('rounds.editSuccess'));
-                       if (onCancel) {
-                               onCancel();
-                       }
-               } catch (e) {
-                       toastr.error(i18n.t('rounds.editError'));
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ round }) => ({
-               code: round.code || [],
-               game: round.game || 'mixed',
-               rolled_by: round.rolled_by || null,
-               round_id: round.id,
-               seed: round.seed || '',
-               spoiler: round.spoiler || '',
-               title: round.title || '',
-       }),
-       validationSchema: yup.object().shape({
-               code: yup.array().of(yup.string()),
-               rolled_by: yup.string().nullable(),
-               seed: yup.string().url(),
-               spoiler: yup.string().url(),
-               title: yup.string(),
-       }),
-})(withTranslation()(EditForm));
diff --git a/resources/js/components/rounds/EditForm.jsx b/resources/js/components/rounds/EditForm.jsx
new file mode 100644 (file)
index 0000000..ac2cd42
--- /dev/null
@@ -0,0 +1,195 @@
+import axios from 'axios';
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import SeedCodeInput from './SeedCodeInput';
+import UserSelect from '../common/UserSelect';
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import i18n from '../../i18n';
+import yup from '../../schema/yup';
+
+const EditForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       touched,
+       values,
+}) =>
+<Form noValidate onSubmit={handleSubmit}>
+       <Modal.Body>
+               <Row>
+                       <Form.Group as={Col} controlId="round.title">
+                               <Form.Label>{i18n.t('rounds.title')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.title && errors.title)}
+                                       name="title"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="text"
+                                       value={values.title || ''}
+                               />
+                               {touched.title && errors.title ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {i18n.t(errors.title)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+               <Row>
+                       <Form.Group as={Col} controlId="round.seed">
+                               <Form.Label>{i18n.t('rounds.seed')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.seed && errors.seed)}
+                                       name="seed"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="text"
+                                       value={values.seed || ''}
+                               />
+                               {touched.seed && errors.seed ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {i18n.t(errors.seed)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+               <Row>
+                       <Form.Group as={Col} controlId="round.spoiler">
+                               <Form.Label>{i18n.t('rounds.spoiler')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.spoiler && errors.spoiler)}
+                                       name="spoiler"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="text"
+                                       value={values.spoiler || ''}
+                               />
+                               {touched.spoiler && errors.spoiler ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {i18n.t(errors.spoiler)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+               <Row>
+                       <Form.Group as={Col}>
+                               <Form.Label>{i18n.t('rounds.code')}</Form.Label>
+                               <Form.Control
+                                       as={SeedCodeInput}
+                                       game={values.game || 'mixed'}
+                                       isInvalid={!!(touched.code && errors.code)}
+                                       name="code"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.code || []}
+                               />
+                               {touched.code && errors.code ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {i18n.t(errors.code)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+               <Row>
+                       <Form.Group as={Col}>
+                               <Form.Label>{i18n.t('rounds.rolled_by')}</Form.Label>
+                               <Form.Control
+                                       as={UserSelect}
+                                       isInvalid={!!(touched.rolled_by && errors.rolled_by)}
+                                       name="rolled_by"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.rolled_by || null}
+                               />
+                               {touched.rolled_by && errors.rolled_by ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {i18n.t(errors.rolled_by)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+       </Modal.Body>
+       <Modal.Footer>
+               {onCancel ?
+                       <Button onClick={onCancel} variant="secondary">
+                               {i18n.t('button.cancel')}
+                       </Button>
+               : null}
+               <Button type="submit" variant="primary">
+                       {i18n.t('button.save')}
+               </Button>
+       </Modal.Footer>
+</Form>;
+
+EditForm.propTypes = {
+       errors: PropTypes.shape({
+               code: PropTypes.arrayOf(PropTypes.string),
+               rolled_by: PropTypes.string,
+               seed: PropTypes.string,
+               spoiler: PropTypes.string,
+               title: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               code: PropTypes.arrayOf(PropTypes.bool),
+               rolled_by: PropTypes.bool,
+               seed: PropTypes.bool,
+               spoiler: PropTypes.bool,
+               title: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               code: PropTypes.arrayOf(PropTypes.string),
+               game: PropTypes.string,
+               rolled_by: PropTypes.string,
+               seed: PropTypes.string,
+               spoiler: PropTypes.string,
+               title: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'EditForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { round_id } = values;
+               const { setErrors } = actions;
+               const { onCancel } = actions.props;
+               try {
+                       await axios.put(`/api/rounds/${round_id}`, values);
+                       toastr.success(i18n.t('rounds.editSuccess'));
+                       if (onCancel) {
+                               onCancel();
+                       }
+               } catch (e) {
+                       toastr.error(i18n.t('rounds.editError'));
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ round }) => ({
+               code: round.code || [],
+               game: round.game || 'mixed',
+               rolled_by: round.rolled_by || null,
+               round_id: round.id,
+               seed: round.seed || '',
+               spoiler: round.spoiler || '',
+               title: round.title || '',
+       }),
+       validationSchema: yup.object().shape({
+               code: yup.array().of(yup.string()),
+               rolled_by: yup.string().nullable(),
+               seed: yup.string().url(),
+               spoiler: yup.string().url(),
+               title: yup.string(),
+       }),
+})(withTranslation()(EditForm));
diff --git a/resources/js/components/rounds/Item.js b/resources/js/components/rounds/Item.js
deleted file mode 100644 (file)
index 0ef77c5..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-import EditButton from './EditButton';
-import LockButton from './LockButton';
-import SeedButton from './SeedButton';
-import SeedCode from './SeedCode';
-import SeedRolledBy from './SeedRolledBy';
-import List from '../results/List';
-import ReportButton from '../results/ReportButton';
-import { mayEditRound, mayReportResult, isRunner } from '../../helpers/permissions';
-import { isComplete } from '../../helpers/Round';
-import { hasFinishedRound } from '../../helpers/User';
-import { useUser } from '../../hooks/user';
-
-const getClassName = (round, tournament, user) => {
-       const classNames = ['round'];
-       if (round.locked) {
-               classNames.push('is-locked');
-       } else {
-               classNames.push('is-unlocked');
-       }
-       if (isComplete(tournament, round)) {
-               classNames.push('is-complete');
-       } else {
-               classNames.push('is-incomplete');
-       }
-       if (hasFinishedRound(user, round)) {
-               classNames.push('has-finished');
-       } else if (isRunner(user, tournament)) {
-               classNames.push('has-not-finished');
-       }
-       return classNames.join(' ');
-};
-
-const Item = ({
-       round,
-       tournament,
-}) => {
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-return <li className={getClassName(round, tournament, user)}>
-               {round.title ?
-                       <h3>{round.title}</h3>
-               : null}
-               <div className="d-flex">
-                       <div className="info">
-                               <p className="date">
-                                       {tournament.show_numbers && round.number ? `#${round.number} ` : ''}
-                                       {t('rounds.date', { date: new Date(round.created_at) })}
-                               </p>
-                               <p className="seed">
-                                       {round.code && round.code.length ?
-                                               <>
-                                                       <SeedCode code={round.code} game={round.game || 'alttpr'} />
-                                                       <br />
-                                               </>
-                                       : null}
-                                       <SeedButton
-                                               round={round}
-                                               tournament={tournament}
-                                       />
-                                       {' '}
-                                       <SeedRolledBy round={round} />
-                               </p>
-                               {mayReportResult(user, tournament) ?
-                                       <p className="report">
-                                               <ReportButton
-                                                       round={round}
-                                                       tournament={tournament}
-                                                       user={user}
-                                               />
-                                       </p>
-                               : null}
-                               {tournament.type === 'open-async' && round.results && round.results.length ?
-                                       <p>{t('rounds.numberOfResults', { count: round.results.length })}</p>
-                               : null}
-                               <div className="button-bar">
-                                       <LockButton round={round} tournament={tournament} />
-                                       {mayEditRound(user, tournament, round) ?
-                                               <EditButton round={round} tournament={tournament} />
-                                       : null}
-                               </div>
-                       </div>
-                       <List round={round} tournament={tournament} />
-               </div>
-       </li>;
-};
-
-Item.propTypes = {
-       round: PropTypes.shape({
-               code: PropTypes.arrayOf(PropTypes.string),
-               created_at: PropTypes.string,
-               game: PropTypes.string,
-               locked: PropTypes.bool,
-               number: PropTypes.number,
-               results: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               seed: PropTypes.string,
-               title: PropTypes.string,
-       }),
-       tournament: PropTypes.shape({
-               participants: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               show_numbers: PropTypes.bool,
-               type: PropTypes.string,
-       }),
-};
-
-export default Item;
diff --git a/resources/js/components/rounds/Item.jsx b/resources/js/components/rounds/Item.jsx
new file mode 100644 (file)
index 0000000..9cd095f
--- /dev/null
@@ -0,0 +1,130 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import DeleteButton from './DeleteButton';
+import EditButton from './EditButton';
+import LockButton from './LockButton';
+import SeedButton from './SeedButton';
+import SeedCode from './SeedCode';
+import SeedRolledBy from './SeedRolledBy';
+import RoundProtocol from '../protocol/RoundProtocol';
+import List from '../results/List';
+import ReportButton from '../results/ReportButton';
+import {
+       mayDeleteRound,
+       mayEditRound,
+       mayReportResult,
+       mayViewProtocol,
+       isRunner,
+} from '../../helpers/permissions';
+import { isComplete } from '../../helpers/Round';
+import { hasFinishedRound } from '../../helpers/User';
+import { useUser } from '../../hooks/user';
+
+const getClassName = (round, tournament, user) => {
+       const classNames = ['round'];
+       if (round.locked) {
+               classNames.push('is-locked');
+       } else {
+               classNames.push('is-unlocked');
+       }
+       if (isComplete(tournament, round)) {
+               classNames.push('is-complete');
+       } else {
+               classNames.push('is-incomplete');
+       }
+       if (hasFinishedRound(user, round)) {
+               classNames.push('has-finished');
+       } else if (isRunner(user, tournament)) {
+               classNames.push('has-not-finished');
+       }
+       return classNames.join(' ');
+};
+
+const Item = ({
+       round,
+       tournament,
+}) => {
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       return <li className={getClassName(round, tournament, user)}>
+               {round.title ?
+                       <h3>{round.title}</h3>
+               : null}
+               <div className="d-flex">
+                       <div className="info">
+                               <p className="date">
+                                       {tournament.show_numbers && round.number ? `#${round.number} ` : ''}
+                                       {t('rounds.date', { date: new Date(round.created_at) })}
+                               </p>
+                               <p className="seed">
+                                       {round.code && round.code.length ?
+                                               <>
+                                                       <SeedCode code={round.code} game={round.game || 'alttpr'} />
+                                                       <br />
+                                               </>
+                                       : null}
+                                       <SeedButton
+                                               round={round}
+                                               tournament={tournament}
+                                       />
+                                       {' '}
+                                       <SeedRolledBy round={round} />
+                               </p>
+                               {mayReportResult(user, tournament) ?
+                                       <p className="report">
+                                               <ReportButton
+                                                       round={round}
+                                                       tournament={tournament}
+                                                       user={user}
+                                               />
+                                       </p>
+                               : null}
+                               <div className="bottom-half">
+                                       {tournament.type === 'open-async' && round.results && round.results.length ?
+                                               <p>{t('rounds.numberOfResults', { count: round.results.length })}</p>
+                                       : null}
+                                       <div className="button-bar">
+                                               <LockButton round={round} tournament={tournament} />
+                                               {mayEditRound(user, tournament, round) ?
+                                                       <EditButton round={round} tournament={tournament} />
+                                               : null}
+                                               {mayViewProtocol(user, tournament, round) ?
+                                                       <RoundProtocol roundId={round.id} tournamentId={tournament.id} />
+                                               : null}
+                                               {mayDeleteRound(user, tournament, round) ?
+                                                       <DeleteButton round={round} tournament={tournament} />
+                                               : null}
+                                       </div>
+                               </div>
+                       </div>
+                       <List round={round} tournament={tournament} />
+               </div>
+       </li>;
+};
+
+Item.propTypes = {
+       round: PropTypes.shape({
+               code: PropTypes.arrayOf(PropTypes.string),
+               created_at: PropTypes.string,
+               game: PropTypes.string,
+               id: PropTypes.number,
+               locked: PropTypes.bool,
+               number: PropTypes.number,
+               results: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               seed: PropTypes.string,
+               title: PropTypes.string,
+       }),
+       tournament: PropTypes.shape({
+               participants: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               id: PropTypes.number,
+               show_numbers: PropTypes.bool,
+               type: PropTypes.string,
+       }),
+};
+
+export default Item;
diff --git a/resources/js/components/rounds/List.js b/resources/js/components/rounds/List.js
deleted file mode 100644 (file)
index 5aa2a4c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import Item from './Item';
-import LoadMore from './LoadMore';
-import i18n from '../../i18n';
-
-const List = ({
-       loadMore,
-       rounds,
-       tournament,
-}) => rounds && rounds.length ? <>
-       <ol className="rounds">
-               {rounds.map(round =>
-                       <Item
-                               key={round.id}
-                               round={round}
-                               tournament={tournament}
-                       />
-               )}
-       </ol>
-       {loadMore ?
-               <LoadMore loadMore={loadMore} />
-       : null}
-</> :
-       <Alert variant="info">
-               {i18n.t('rounds.empty')}
-       </Alert>
-;
-
-List.propTypes = {
-       loadMore: PropTypes.func,
-       rounds: PropTypes.arrayOf(PropTypes.shape({
-               id: PropTypes.number,
-       })),
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(List);
diff --git a/resources/js/components/rounds/List.jsx b/resources/js/components/rounds/List.jsx
new file mode 100644 (file)
index 0000000..5aa2a4c
--- /dev/null
@@ -0,0 +1,42 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import Item from './Item';
+import LoadMore from './LoadMore';
+import i18n from '../../i18n';
+
+const List = ({
+       loadMore,
+       rounds,
+       tournament,
+}) => rounds && rounds.length ? <>
+       <ol className="rounds">
+               {rounds.map(round =>
+                       <Item
+                               key={round.id}
+                               round={round}
+                               tournament={tournament}
+                       />
+               )}
+       </ol>
+       {loadMore ?
+               <LoadMore loadMore={loadMore} />
+       : null}
+</> :
+       <Alert variant="info">
+               {i18n.t('rounds.empty')}
+       </Alert>
+;
+
+List.propTypes = {
+       loadMore: PropTypes.func,
+       rounds: PropTypes.arrayOf(PropTypes.shape({
+               id: PropTypes.number,
+       })),
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(List);
diff --git a/resources/js/components/rounds/LoadMore.js b/resources/js/components/rounds/LoadMore.js
deleted file mode 100644 (file)
index d0ea365..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-const LoadMore = ({ loadMore }) => {
-       const [loading, setLoading] = React.useState(false);
-
-       const { t } = useTranslation();
-
-       const handleLoadMore = React.useCallback(async () => {
-               setLoading(true);
-               try {
-                       await loadMore();
-               } finally {
-                       setLoading(false);
-               }
-       }, [loadMore]);
-
-       return <div className="d-grid mt-2">
-               <Button disabled={loading} onClick={handleLoadMore} variant="outline-secondary">
-               {t('rounds.loadMore')}
-               </Button>
-       </div>;
-};
-
-LoadMore.propTypes = {
-       loadMore: PropTypes.func,
-};
-
-export default LoadMore;
diff --git a/resources/js/components/rounds/LoadMore.jsx b/resources/js/components/rounds/LoadMore.jsx
new file mode 100644 (file)
index 0000000..d0ea365
--- /dev/null
@@ -0,0 +1,31 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const LoadMore = ({ loadMore }) => {
+       const [loading, setLoading] = React.useState(false);
+
+       const { t } = useTranslation();
+
+       const handleLoadMore = React.useCallback(async () => {
+               setLoading(true);
+               try {
+                       await loadMore();
+               } finally {
+                       setLoading(false);
+               }
+       }, [loadMore]);
+
+       return <div className="d-grid mt-2">
+               <Button disabled={loading} onClick={handleLoadMore} variant="outline-secondary">
+               {t('rounds.loadMore')}
+               </Button>
+       </div>;
+};
+
+LoadMore.propTypes = {
+       loadMore: PropTypes.func,
+};
+
+export default LoadMore;
diff --git a/resources/js/components/rounds/LockButton.js b/resources/js/components/rounds/LockButton.js
deleted file mode 100644 (file)
index c29b3d3..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import LockDialog from './LockDialog';
-import Icon from '../common/Icon';
-import { mayLockRound } from '../../helpers/permissions';
-import { useUser } from '../../hooks/user';
-
-const LockButton = ({
-       round,
-       tournament,
-}) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       if (!mayLockRound(user, tournament, round)) {
-               if (round.locked) {
-                       return <Icon.LOCKED title={t('rounds.locked')} />;
-               } else {
-                       return <Icon.UNLOCKED title={t('rounds.unlocked')} />;
-               }
-       }
-
-       return <>
-               <LockDialog
-                       onHide={() => setShowDialog(false)}
-                       round={round}
-                       show={showDialog}
-                       tournament={tournament}
-               />
-               <Button
-                       onClick={() => setShowDialog(true)}
-                       size="sm"
-                       title={t(round.locked ? 'rounds.locked' : 'rounds.unlocked')}
-                       variant="outline-secondary"
-               >
-                       {round.locked ?
-                               <Icon.LOCKED title="" />
-                       :
-                               <Icon.UNLOCKED title="" />
-                       }
-               </Button>
-       </>;
-};
-
-LockButton.propTypes = {
-       round: PropTypes.shape({
-               locked: PropTypes.bool,
-       }),
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default LockButton;
diff --git a/resources/js/components/rounds/LockButton.jsx b/resources/js/components/rounds/LockButton.jsx
new file mode 100644 (file)
index 0000000..c29b3d3
--- /dev/null
@@ -0,0 +1,58 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import LockDialog from './LockDialog';
+import Icon from '../common/Icon';
+import { mayLockRound } from '../../helpers/permissions';
+import { useUser } from '../../hooks/user';
+
+const LockButton = ({
+       round,
+       tournament,
+}) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       if (!mayLockRound(user, tournament, round)) {
+               if (round.locked) {
+                       return <Icon.LOCKED title={t('rounds.locked')} />;
+               } else {
+                       return <Icon.UNLOCKED title={t('rounds.unlocked')} />;
+               }
+       }
+
+       return <>
+               <LockDialog
+                       onHide={() => setShowDialog(false)}
+                       round={round}
+                       show={showDialog}
+                       tournament={tournament}
+               />
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       size="sm"
+                       title={t(round.locked ? 'rounds.locked' : 'rounds.unlocked')}
+                       variant="outline-secondary"
+               >
+                       {round.locked ?
+                               <Icon.LOCKED title="" />
+                       :
+                               <Icon.UNLOCKED title="" />
+                       }
+               </Button>
+       </>;
+};
+
+LockButton.propTypes = {
+       round: PropTypes.shape({
+               locked: PropTypes.bool,
+       }),
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default LockButton;
diff --git a/resources/js/components/rounds/LockDialog.js b/resources/js/components/rounds/LockDialog.js
deleted file mode 100644 (file)
index 6174dbf..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Button, Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import { isComplete } from '../../helpers/Round';
-import i18n from '../../i18n';
-
-const LockDialog = ({
-       onHide,
-       round,
-       show,
-       tournament,
-}) =>
-<Modal className="lock-dialog" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t(round.locked ? 'rounds.unlock' : 'rounds.lock')}
-               </Modal.Title>
-       </Modal.Header>
-       <Modal.Body>
-               <p>{i18n.t(round.locked
-                       ? 'rounds.unlockDescription'
-                       : 'rounds.lockDescription')}
-               </p>
-       {!round.locked && tournament.type === 'signup-async' && !isComplete(tournament, round) ?
-               <Alert variant="warning">
-                       {i18n.t('rounds.lockIncompleteWarning')}
-               </Alert>
-       : null}
-       </Modal.Body>
-       <Modal.Footer>
-               {onHide ?
-                       <Button onClick={onHide} variant="secondary">
-                               {i18n.t('button.cancel')}
-                       </Button>
-               : null}
-               <Button
-                       onClick={async () => {
-                               if (round.locked) {
-                                       try {
-                                               await axios.post(`/api/rounds/${round.id}/unlock`);
-                                               toastr.success(i18n.t('rounds.unlockSuccess'));
-                                               onHide();
-                                       } catch (e) {
-                                               toastr.error(i18n.t('rounds.unlockError'));
-                                       }
-                               } else {
-                                       try {
-                                               await axios.post(`/api/rounds/${round.id}/lock`);
-                                               toastr.success(i18n.t('rounds.lockSuccess'));
-                                               onHide();
-                                       } catch (e) {
-                                               toastr.error(i18n.t('rounds.lockError'));
-                                       }
-                               }
-                       }}
-                       variant="primary"
-               >
-                       {i18n.t(round.locked ? 'rounds.unlock' : 'rounds.lock')}
-               </Button>
-       </Modal.Footer>
-</Modal>;
-
-LockDialog.propTypes = {
-       onHide: PropTypes.func,
-       round: PropTypes.shape({
-               id: PropTypes.number,
-               locked: PropTypes.bool,
-       }),
-       show: PropTypes.bool,
-       tournament: PropTypes.shape({
-               type: PropTypes.string,
-       }),
-};
-
-export default withTranslation()(LockDialog);
diff --git a/resources/js/components/rounds/LockDialog.jsx b/resources/js/components/rounds/LockDialog.jsx
new file mode 100644 (file)
index 0000000..6174dbf
--- /dev/null
@@ -0,0 +1,79 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import { isComplete } from '../../helpers/Round';
+import i18n from '../../i18n';
+
+const LockDialog = ({
+       onHide,
+       round,
+       show,
+       tournament,
+}) =>
+<Modal className="lock-dialog" onHide={onHide} show={show}>
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t(round.locked ? 'rounds.unlock' : 'rounds.lock')}
+               </Modal.Title>
+       </Modal.Header>
+       <Modal.Body>
+               <p>{i18n.t(round.locked
+                       ? 'rounds.unlockDescription'
+                       : 'rounds.lockDescription')}
+               </p>
+       {!round.locked && tournament.type === 'signup-async' && !isComplete(tournament, round) ?
+               <Alert variant="warning">
+                       {i18n.t('rounds.lockIncompleteWarning')}
+               </Alert>
+       : null}
+       </Modal.Body>
+       <Modal.Footer>
+               {onHide ?
+                       <Button onClick={onHide} variant="secondary">
+                               {i18n.t('button.cancel')}
+                       </Button>
+               : null}
+               <Button
+                       onClick={async () => {
+                               if (round.locked) {
+                                       try {
+                                               await axios.post(`/api/rounds/${round.id}/unlock`);
+                                               toastr.success(i18n.t('rounds.unlockSuccess'));
+                                               onHide();
+                                       } catch (e) {
+                                               toastr.error(i18n.t('rounds.unlockError'));
+                                       }
+                               } else {
+                                       try {
+                                               await axios.post(`/api/rounds/${round.id}/lock`);
+                                               toastr.success(i18n.t('rounds.lockSuccess'));
+                                               onHide();
+                                       } catch (e) {
+                                               toastr.error(i18n.t('rounds.lockError'));
+                                       }
+                               }
+                       }}
+                       variant="primary"
+               >
+                       {i18n.t(round.locked ? 'rounds.unlock' : 'rounds.lock')}
+               </Button>
+       </Modal.Footer>
+</Modal>;
+
+LockDialog.propTypes = {
+       onHide: PropTypes.func,
+       round: PropTypes.shape({
+               id: PropTypes.number,
+               locked: PropTypes.bool,
+       }),
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+               type: PropTypes.string,
+       }),
+};
+
+export default withTranslation()(LockDialog);
diff --git a/resources/js/components/rounds/SeedButton.js b/resources/js/components/rounds/SeedButton.js
deleted file mode 100644 (file)
index 59bc3ba..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import SeedDialog from './SeedDialog';
-import { maySetSeed } from '../../helpers/permissions';
-import { useUser } from '../../hooks/user';
-
-const SeedButton = ({ round, tournament }) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       if (round.seed) {
-               return <>
-                       <Button href={round.seed} target="_blank" variant="primary">
-                               {t('rounds.seed')}
-                       </Button>
-                       {round.spoiler ?
-                               <Button
-                                       className="ms-2"
-                                       href={round.spoiler}
-                                       target="_blank"
-                                       variant="outline-primary"
-                               >
-                                       {t('rounds.spoiler')}
-                               </Button>
-                       : null}
-               </>;
-       }
-       if (maySetSeed(user, tournament, round)) {
-               return <>
-                       <SeedDialog
-                               onHide={() => setShowDialog(false)}
-                               round={round}
-                               show={showDialog}
-                       />
-                       <Button onClick={() => setShowDialog(true)} variant="outline-primary">
-                               {t('rounds.setSeed')}
-                       </Button>
-               </>;
-       }
-       return t('rounds.noSeed');
-};
-
-SeedButton.propTypes = {
-       round: PropTypes.shape({
-               seed: PropTypes.string,
-               spoiler: PropTypes.string,
-       }),
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default SeedButton;
diff --git a/resources/js/components/rounds/SeedButton.jsx b/resources/js/components/rounds/SeedButton.jsx
new file mode 100644 (file)
index 0000000..59bc3ba
--- /dev/null
@@ -0,0 +1,57 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import SeedDialog from './SeedDialog';
+import { maySetSeed } from '../../helpers/permissions';
+import { useUser } from '../../hooks/user';
+
+const SeedButton = ({ round, tournament }) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       if (round.seed) {
+               return <>
+                       <Button href={round.seed} target="_blank" variant="primary">
+                               {t('rounds.seed')}
+                       </Button>
+                       {round.spoiler ?
+                               <Button
+                                       className="ms-2"
+                                       href={round.spoiler}
+                                       target="_blank"
+                                       variant="outline-primary"
+                               >
+                                       {t('rounds.spoiler')}
+                               </Button>
+                       : null}
+               </>;
+       }
+       if (maySetSeed(user, tournament, round)) {
+               return <>
+                       <SeedDialog
+                               onHide={() => setShowDialog(false)}
+                               round={round}
+                               show={showDialog}
+                       />
+                       <Button onClick={() => setShowDialog(true)} variant="outline-primary">
+                               {t('rounds.setSeed')}
+                       </Button>
+               </>;
+       }
+       return t('rounds.noSeed');
+};
+
+SeedButton.propTypes = {
+       round: PropTypes.shape({
+               seed: PropTypes.string,
+               spoiler: PropTypes.string,
+       }),
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default SeedButton;
diff --git a/resources/js/components/rounds/SeedCode.js b/resources/js/components/rounds/SeedCode.js
deleted file mode 100644 (file)
index 2f74279..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import ZeldaIcon from '../common/ZeldaIcon';
-
-const SeedCode = ({ code, game }) =>
-<span className={`seed-code game-${game}`}>
-       {code.map(game === 'smr'
-               ? (symbol, index) => <span key={`${symbol}.${index}`}>{symbol}</span>
-               : (symbol, index) => <ZeldaIcon key={`${symbol}.${index}`} name={symbol} />
-       )}
-</span>;
-
-SeedCode.propTypes = {
-       code: PropTypes.arrayOf(PropTypes.string),
-       game: PropTypes.string,
-};
-
-export default SeedCode;
diff --git a/resources/js/components/rounds/SeedCode.jsx b/resources/js/components/rounds/SeedCode.jsx
new file mode 100644 (file)
index 0000000..2f74279
--- /dev/null
@@ -0,0 +1,19 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import ZeldaIcon from '../common/ZeldaIcon';
+
+const SeedCode = ({ code, game }) =>
+<span className={`seed-code game-${game}`}>
+       {code.map(game === 'smr'
+               ? (symbol, index) => <span key={`${symbol}.${index}`}>{symbol}</span>
+               : (symbol, index) => <ZeldaIcon key={`${symbol}.${index}`} name={symbol} />
+       )}
+</span>;
+
+SeedCode.propTypes = {
+       code: PropTypes.arrayOf(PropTypes.string),
+       game: PropTypes.string,
+};
+
+export default SeedCode;
diff --git a/resources/js/components/rounds/SeedCodeInput.js b/resources/js/components/rounds/SeedCodeInput.js
deleted file mode 100644 (file)
index 2431ca3..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Form } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import i18n from '../../i18n';
-
-const ALTTPR_CODES = [
-       'big-key',
-       'blue-boomerang',
-       'bomb',
-       'bombos',
-       'book',
-       'boots',
-       'bottle',
-       'bow',
-       'bugnet',
-       'cape',
-       'compass',
-       'ether',
-       'flippers',
-       'flute',
-       'glove',
-       'green-mail',
-       'green-pendant',
-       'green-potion',
-       'hammer',
-       'heart-container',
-       'hookshot',
-       'ice-rod',
-       'lamp',
-       'map',
-       'mirror',
-       'mirror-shield',
-       'moonpearl',
-       'mushroom',
-       'powder',
-       'quake',
-       'shovel',
-       'somaria',
-];
-
-const SMR_CODES = [
-       'ALCOON',
-       'ATOMIC',
-       'BEETOM',
-       'BOYON',
-       'BULL',
-       'CHOOT',
-       'COVERN',
-       'EVIR',
-       'FUNE',
-       'GAMET',
-       'GEEMER',
-       'GERUTA',
-       'HOLTZ',
-       'KAGO',
-       'NAMIHE',
-       'OUM',
-       'OWTCH',
-       'POWAMP',
-       'PUROMI',
-       'PUYO',
-       'RINKA',
-       'RIPPER',
-       'SCISER',
-       'SKREE',
-       'SOVA',
-       'TATORI',
-       'VIOLA',
-       'WAVER',
-       'YARD',
-       'ZEBBO',
-       'ZEELA',
-       'ZOA',
-];
-
-const SeedCodeInput = ({
-       className,
-       game,
-       name,
-       onBlur,
-       onChange,
-       value,
-}) => {
-       if (game === 'alttpr') {
-               const code_trans = ALTTPR_CODES
-                       .map(code => ({ code, label: i18n.t(`icon.zelda.${code}`)}))
-                       .sort((a, b) => a.label.localeCompare(b.label));
-               return <div
-                       className={`${className} seed-code-input game-alttpr`}
-               >
-                       {[0, 1, 2, 3, 4].map(num =>
-                               <Form.Select
-                                       key={num}
-                                       onBlur={onBlur}
-                                       onChange={onChange}
-                                       name={`${name}[${num}]`}
-                                       value={(value && value[num]) || ''}
-                               >
-                                       <option value=""></option>
-                                       {code_trans.map(({ code, label }) =>
-                                               <option key={code} value={code}>{label}</option>
-                                       )}
-                               </Form.Select>
-                       )}
-               </div>;
-       }
-       if (game === 'smr') {
-               return <div
-                       className={`${className} seed-code-input game-smr`}
-               >
-                       {[0, 1, 2, 3].map(num =>
-                               <Form.Select
-                                       key={num}
-                                       onBlur={onBlur}
-                                       onChange={onChange}
-                                       name={`${name}[${num}]`}
-                                       value={(value && value[num]) || ''}
-                               >
-                                       <option value=""></option>
-                                       {SMR_CODES.sort((a, b) => a.localeCompare(b)).map(code =>
-                                               <option key={code} value={code}>{code}</option>
-                                       )}
-                               </Form.Select>
-                       )}
-               </div>;
-       }
-       return <div
-               className={`${className} seed-code-input`}
-       >
-               {[0, 1, 2, 3, 4].map(num =>
-                       <Form.Control
-                               key={num}
-                               onBlur={onBlur}
-                               onChange={onChange}
-                               name={`${name}[${num}]`}
-                               value={(value && value[num]) || ''}
-                       />
-               )}
-       </div>;
-};
-
-SeedCodeInput.propTypes = {
-       className: PropTypes.string,
-       game: PropTypes.string,
-       name: PropTypes.string,
-       onBlur: PropTypes.func,
-       onChange: PropTypes.func,
-       value: PropTypes.arrayOf(PropTypes.string),
-};
-
-SeedCodeInput.defaultProps = {
-       className: '',
-       game: '',
-       name: '',
-       onBlur: null,
-       onChange: null,
-       value: [],
-};
-
-export default withTranslation()(SeedCodeInput);
diff --git a/resources/js/components/rounds/SeedCodeInput.jsx b/resources/js/components/rounds/SeedCodeInput.jsx
new file mode 100644 (file)
index 0000000..958c927
--- /dev/null
@@ -0,0 +1,153 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Form } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import i18n from '../../i18n';
+
+const ALTTPR_CODES = [
+       'big-key',
+       'blue-boomerang',
+       'bomb',
+       'bombos',
+       'book',
+       'boots',
+       'bottle',
+       'bow',
+       'bugnet',
+       'cape',
+       'compass',
+       'ether',
+       'flippers',
+       'flute',
+       'glove',
+       'green-mail',
+       'green-pendant',
+       'green-potion',
+       'hammer',
+       'heart-container',
+       'hookshot',
+       'ice-rod',
+       'lamp',
+       'map',
+       'mirror',
+       'mirror-shield',
+       'moonpearl',
+       'mushroom',
+       'powder',
+       'quake',
+       'shovel',
+       'somaria',
+];
+
+const SMR_CODES = [
+       'ALCOON',
+       'ATOMIC',
+       'BEETOM',
+       'BOYON',
+       'BULL',
+       'CHOOT',
+       'COVERN',
+       'EVIR',
+       'FUNE',
+       'GAMET',
+       'GEEMER',
+       'GERUTA',
+       'HOLTZ',
+       'KAGO',
+       'NAMIHE',
+       'OUM',
+       'OWTCH',
+       'POWAMP',
+       'PUROMI',
+       'PUYO',
+       'RINKA',
+       'RIPPER',
+       'SCISER',
+       'SKREE',
+       'SOVA',
+       'TATORI',
+       'VIOLA',
+       'WAVER',
+       'YARD',
+       'ZEBBO',
+       'ZEELA',
+       'ZOA',
+];
+
+const SeedCodeInput = ({
+       className = '',
+       game = '',
+       name = '',
+       onBlur = null,
+       onChange = null,
+       value = [],
+}) => {
+       if (game === 'alttpr') {
+               const code_trans = ALTTPR_CODES
+                       .map(code => ({ code, label: i18n.t(`icon.zelda.${code}`)}))
+                       .sort((a, b) => a.label.localeCompare(b.label));
+               return <div
+                       className={`${className} seed-code-input game-alttpr`}
+               >
+                       {[0, 1, 2, 3, 4].map(num =>
+                               <Form.Select
+                                       key={num}
+                                       onBlur={onBlur}
+                                       onChange={onChange}
+                                       name={`${name}[${num}]`}
+                                       value={(value && value[num]) || ''}
+                               >
+                                       <option value=""></option>
+                                       {code_trans.map(({ code, label }) =>
+                                               <option key={code} value={code}>{label}</option>
+                                       )}
+                               </Form.Select>
+                       )}
+               </div>;
+       }
+       if (game === 'smr') {
+               return <div
+                       className={`${className} seed-code-input game-smr`}
+               >
+                       {[0, 1, 2, 3].map(num =>
+                               <Form.Select
+                                       key={num}
+                                       onBlur={onBlur}
+                                       onChange={onChange}
+                                       name={`${name}[${num}]`}
+                                       value={(value && value[num]) || ''}
+                               >
+                                       <option value=""></option>
+                                       {SMR_CODES.sort((a, b) => a.localeCompare(b)).map(code =>
+                                               <option key={code} value={code}>{code}</option>
+                                       )}
+                               </Form.Select>
+                       )}
+               </div>;
+       }
+       return <div
+               className={`${className} seed-code-input`}
+       >
+               {[0, 1, 2, 3, 4].map(num =>
+                       <Form.Control
+                               key={num}
+                               onBlur={onBlur}
+                               onChange={onChange}
+                               name={`${name}[${num}]`}
+                               value={(value && value[num]) || ''}
+                       />
+               )}
+       </div>;
+};
+
+SeedCodeInput.propTypes = {
+       className: PropTypes.string,
+       game: PropTypes.string,
+       name: PropTypes.string,
+       onBlur: PropTypes.func,
+       onChange: PropTypes.func,
+       value: PropTypes.arrayOf(PropTypes.string),
+};
+
+export default withTranslation()(SeedCodeInput);
diff --git a/resources/js/components/rounds/SeedDialog.js b/resources/js/components/rounds/SeedDialog.js
deleted file mode 100644 (file)
index 2ee3658..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import SeedForm from './SeedForm';
-import i18n from '../../i18n';
-
-const SeedDialog = ({
-       onHide,
-       round,
-       show,
-}) =>
-<Modal className="seed-dialog" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('rounds.setSeed')}
-               </Modal.Title>
-       </Modal.Header>
-       <SeedForm
-               onCancel={onHide}
-               round={round}
-       />
-</Modal>;
-
-SeedDialog.propTypes = {
-       onHide: PropTypes.func,
-       round: PropTypes.shape({
-       }),
-       show: PropTypes.bool,
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(SeedDialog);
diff --git a/resources/js/components/rounds/SeedDialog.jsx b/resources/js/components/rounds/SeedDialog.jsx
new file mode 100644 (file)
index 0000000..2ee3658
--- /dev/null
@@ -0,0 +1,35 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import SeedForm from './SeedForm';
+import i18n from '../../i18n';
+
+const SeedDialog = ({
+       onHide,
+       round,
+       show,
+}) =>
+<Modal className="seed-dialog" onHide={onHide} show={show}>
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t('rounds.setSeed')}
+               </Modal.Title>
+       </Modal.Header>
+       <SeedForm
+               onCancel={onHide}
+               round={round}
+       />
+</Modal>;
+
+SeedDialog.propTypes = {
+       onHide: PropTypes.func,
+       round: PropTypes.shape({
+       }),
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(SeedDialog);
diff --git a/resources/js/components/rounds/SeedForm.js b/resources/js/components/rounds/SeedForm.js
deleted file mode 100644 (file)
index 3cff560..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-import axios from 'axios';
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import i18n from '../../i18n';
-import yup from '../../schema/yup';
-
-const SeedForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       touched,
-       values,
-}) =>
-<Form noValidate onSubmit={handleSubmit}>
-       <Modal.Body>
-               <Row>
-                       <Form.Group as={Col} controlId="round.seed">
-                               <Form.Label>{i18n.t('rounds.seed')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.seed && errors.seed)}
-                                       name="seed"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       placeholder="https://alttprpatch.synack.live/patcher.html?patch=https://sahasrahbot.s3.amazonaws.com/patch/DR_XXXXXXXXXXX.bps"
-                                       type="text"
-                                       value={values.seed || ''}
-                               />
-                               {touched.seed && errors.seed ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {i18n.t(errors.seed)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-       </Modal.Body>
-       <Modal.Footer>
-               {onCancel ?
-                       <Button onClick={onCancel} variant="secondary">
-                               {i18n.t('button.cancel')}
-                       </Button>
-               : null}
-               <Button type="submit" variant="primary">
-                       {i18n.t('button.save')}
-               </Button>
-       </Modal.Footer>
-</Form>;
-
-SeedForm.propTypes = {
-       errors: PropTypes.shape({
-               seed: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               seed: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               seed: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'SeedForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { round_id, seed } = values;
-               const { setErrors } = actions;
-               const { onCancel } = actions.props;
-               try {
-                       await axios.post(`/api/rounds/${round_id}/setSeed`, {
-                               seed,
-                       });
-                       toastr.success(i18n.t('rounds.setSeedSuccess'));
-                       if (onCancel) {
-                               onCancel();
-                       }
-               } catch (e) {
-                       toastr.error(i18n.t('rounds.setSeedError'));
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ round }) => ({
-               round_id: round.id,
-               seed: round.seed || '',
-       }),
-       validationSchema: yup.object().shape({
-               seed: yup.string().required().url(),
-       }),
-})(withTranslation()(SeedForm));
diff --git a/resources/js/components/rounds/SeedForm.jsx b/resources/js/components/rounds/SeedForm.jsx
new file mode 100644 (file)
index 0000000..3cff560
--- /dev/null
@@ -0,0 +1,101 @@
+import axios from 'axios';
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import i18n from '../../i18n';
+import yup from '../../schema/yup';
+
+const SeedForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       touched,
+       values,
+}) =>
+<Form noValidate onSubmit={handleSubmit}>
+       <Modal.Body>
+               <Row>
+                       <Form.Group as={Col} controlId="round.seed">
+                               <Form.Label>{i18n.t('rounds.seed')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.seed && errors.seed)}
+                                       name="seed"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       placeholder="https://alttprpatch.synack.live/patcher.html?patch=https://sahasrahbot.s3.amazonaws.com/patch/DR_XXXXXXXXXXX.bps"
+                                       type="text"
+                                       value={values.seed || ''}
+                               />
+                               {touched.seed && errors.seed ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {i18n.t(errors.seed)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+       </Modal.Body>
+       <Modal.Footer>
+               {onCancel ?
+                       <Button onClick={onCancel} variant="secondary">
+                               {i18n.t('button.cancel')}
+                       </Button>
+               : null}
+               <Button type="submit" variant="primary">
+                       {i18n.t('button.save')}
+               </Button>
+       </Modal.Footer>
+</Form>;
+
+SeedForm.propTypes = {
+       errors: PropTypes.shape({
+               seed: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               seed: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               seed: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'SeedForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { round_id, seed } = values;
+               const { setErrors } = actions;
+               const { onCancel } = actions.props;
+               try {
+                       await axios.post(`/api/rounds/${round_id}/setSeed`, {
+                               seed,
+                       });
+                       toastr.success(i18n.t('rounds.setSeedSuccess'));
+                       if (onCancel) {
+                               onCancel();
+                       }
+               } catch (e) {
+                       toastr.error(i18n.t('rounds.setSeedError'));
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ round }) => ({
+               round_id: round.id,
+               seed: round.seed || '',
+       }),
+       validationSchema: yup.object().shape({
+               seed: yup.string().required().url(),
+       }),
+})(withTranslation()(SeedForm));
diff --git a/resources/js/components/rounds/SeedRolledBy.js b/resources/js/components/rounds/SeedRolledBy.js
deleted file mode 100644 (file)
index cf73401..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import { getAvatarUrl, getUserName } from '../../helpers/User';
-import i18n from '../../i18n';
-
-const SeedRolledBy = ({ round }) => round.rolled_by_user ?
-       <span
-               className="rolled-by"
-               title={i18n.t('rounds.rolledBy', { name: getUserName(round.rolled_by_user) })}
-       >
-               <img alt={getUserName(round.rolled_by_user)} src={getAvatarUrl(round.rolled_by_user)} />
-       </span>
-: null;
-
-SeedRolledBy.propTypes = {
-       round: PropTypes.shape({
-               rolled_by_user: PropTypes.shape({
-               }),
-       }),
-};
-
-export default SeedRolledBy;
diff --git a/resources/js/components/rounds/SeedRolledBy.jsx b/resources/js/components/rounds/SeedRolledBy.jsx
new file mode 100644 (file)
index 0000000..cf73401
--- /dev/null
@@ -0,0 +1,23 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import { getAvatarUrl, getUserName } from '../../helpers/User';
+import i18n from '../../i18n';
+
+const SeedRolledBy = ({ round }) => round.rolled_by_user ?
+       <span
+               className="rolled-by"
+               title={i18n.t('rounds.rolledBy', { name: getUserName(round.rolled_by_user) })}
+       >
+               <img alt={getUserName(round.rolled_by_user)} src={getAvatarUrl(round.rolled_by_user)} />
+       </span>
+: null;
+
+SeedRolledBy.propTypes = {
+       round: PropTypes.shape({
+               rolled_by_user: PropTypes.shape({
+               }),
+       }),
+};
+
+export default SeedRolledBy;
diff --git a/resources/js/components/snes/SettingsDialog.js b/resources/js/components/snes/SettingsDialog.js
deleted file mode 100644 (file)
index 0f47d8f..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import SettingsForm from './SettingsForm';
-
-const SettingsDialog = ({
-       deviceList,
-       onHide,
-       onSubmit,
-       settings,
-       show,
-}) => {
-       const { t } = useTranslation();
-
-       return <Modal className="snes-settings-dialog" onHide={onHide} show={show}>
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {t('snes.settings')}
-                       </Modal.Title>
-               </Modal.Header>
-               <SettingsForm
-                       deviceList={deviceList}
-                       onCancel={onHide}
-                       onSubmit={onSubmit}
-                       settings={settings}
-               />
-       </Modal>;
-};
-
-SettingsDialog.propTypes = {
-       deviceList: PropTypes.arrayOf(PropTypes.string),
-       onHide: PropTypes.func,
-       onSubmit: PropTypes.func,
-       settings: PropTypes.shape({
-       }),
-       show: PropTypes.bool,
-};
-
-export default SettingsDialog;
diff --git a/resources/js/components/snes/SettingsDialog.jsx b/resources/js/components/snes/SettingsDialog.jsx
new file mode 100644 (file)
index 0000000..0f47d8f
--- /dev/null
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import SettingsForm from './SettingsForm';
+
+const SettingsDialog = ({
+       deviceList,
+       onHide,
+       onSubmit,
+       settings,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal className="snes-settings-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('snes.settings')}
+                       </Modal.Title>
+               </Modal.Header>
+               <SettingsForm
+                       deviceList={deviceList}
+                       onCancel={onHide}
+                       onSubmit={onSubmit}
+                       settings={settings}
+               />
+       </Modal>;
+};
+
+SettingsDialog.propTypes = {
+       deviceList: PropTypes.arrayOf(PropTypes.string),
+       onHide: PropTypes.func,
+       onSubmit: PropTypes.func,
+       settings: PropTypes.shape({
+       }),
+       show: PropTypes.bool,
+};
+
+export default SettingsDialog;
diff --git a/resources/js/components/snes/SettingsForm.js b/resources/js/components/snes/SettingsForm.js
deleted file mode 100644 (file)
index 7e05108..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import yup from '../../schema/yup';
-
-const SettingsForm = ({
-       deviceList,
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       settings,
-       touched,
-       values,
-}) => {
-       const { t } = useTranslation();
-
-       return <Form noValidate onSubmit={handleSubmit}>
-               <Modal.Body>
-                       <Row>
-                               <Form.Group as={Col} sm={3} controlId="snes.proto">
-                                       <Form.Label>{t('snes.proto')}</Form.Label>
-                                       <Form.Select
-                                               isInvalid={!!(touched.proto && errors.proto)}
-                                               name="proto"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               value={values.proto || 'ws'}
-                                       >
-                                               <option value="ws">ws://</option>
-                                               <option value="wss">wss://</option>
-                                       </Form.Select>
-                                       {touched.proto && errors.proto ?
-                                               <Form.Control.Feedback type="invalid">
-                                                       {t(errors.proto)}
-                                               </Form.Control.Feedback>
-                                       : null}
-                               </Form.Group>
-                               <Form.Group as={Col} sm={6} controlId="snes.host">
-                                       <Form.Label>{t('snes.host')}</Form.Label>
-                                       <Form.Control
-                                               isInvalid={!!(touched.host && errors.host)}
-                                               name="host"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               type="text"
-                                               value={values.host || 'localhost'}
-                                       />
-                                       {touched.host && errors.host ?
-                                               <Form.Control.Feedback type="invalid">
-                                                       {t(errors.host)}
-                                               </Form.Control.Feedback>
-                                       : null}
-                               </Form.Group>
-                               <Form.Group as={Col} sm={3} controlId="snes.port">
-                                       <Form.Label>{t('snes.port')}</Form.Label>
-                                       <Form.Control
-                                               isInvalid={!!(touched.port && errors.port)}
-                                               min="1"
-                                               max="65665"
-                                               name="port"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               type="number"
-                                               value={values.port || 8080}
-                                       />
-                                       {touched.port && errors.port ?
-                                               <Form.Control.Feedback type="invalid">
-                                                       {t(errors.port)}
-                                               </Form.Control.Feedback>
-                                       : null}
-                               </Form.Group>
-                               <Form.Group as={Col} sm={12} controlId="snes.device">
-                                       <Form.Label>{t('snes.device')}</Form.Label>
-                                       <Form.Select
-                                               isInvalid={!!(touched.device && errors.device)}
-                                               name="device"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               value={values.device || ''}
-                                       >
-                                               <option value="">Auto</option>
-                                               {settings.device && !deviceList.includes(settings.device) ?
-                                                       <option value={settings.device}>{settings.device}</option>
-                                               : null}
-                                               {deviceList.map(device =>
-                                                       <option key={device} value={device}>{device}</option>
-                                               )}
-                                       </Form.Select>
-                                       {touched.device && errors.device ?
-                                               <Form.Control.Feedback type="invalid">
-                                                       {t(errors.device)}
-                                               </Form.Control.Feedback>
-                                       : null}
-                               </Form.Group>
-                       </Row>
-               </Modal.Body>
-               <Modal.Footer>
-                       {onCancel ?
-                               <Button onClick={onCancel} variant="secondary">
-                                       {t('button.cancel')}
-                               </Button>
-                       : null}
-                       <Button type="submit" variant="primary">
-                               {t('button.save')}
-                       </Button>
-               </Modal.Footer>
-       </Form>;
-};
-
-SettingsForm.propTypes = {
-       deviceList: PropTypes.arrayOf(PropTypes.string),
-       errors: PropTypes.shape({
-               device: PropTypes.string,
-               host: PropTypes.string,
-               port: PropTypes.string,
-               proto: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       settings: PropTypes.shape({
-               device: PropTypes.string,
-               host: PropTypes.string,
-               port: PropTypes.number,
-               proto: PropTypes.string,
-       }),
-       touched: PropTypes.shape({
-               device: PropTypes.bool,
-               host: PropTypes.bool,
-               port: PropTypes.bool,
-               proto: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               device: PropTypes.string,
-               host: PropTypes.string,
-               port: PropTypes.number,
-               proto: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'SettingsForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { onSubmit } = actions.props;
-               onSubmit(values);
-       },
-       mapPropsToValues: ({ settings }) => settings,
-       validationSchema: yup.object().shape({
-               device: yup.string(),
-               host: yup.string(),
-               port: yup.number().min(1).max(65665),
-               proto: yup.string(),
-       }),
-})(SettingsForm);
diff --git a/resources/js/components/snes/SettingsForm.jsx b/resources/js/components/snes/SettingsForm.jsx
new file mode 100644 (file)
index 0000000..7e05108
--- /dev/null
@@ -0,0 +1,161 @@
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import yup from '../../schema/yup';
+
+const SettingsForm = ({
+       deviceList,
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       settings,
+       touched,
+       values,
+}) => {
+       const { t } = useTranslation();
+
+       return <Form noValidate onSubmit={handleSubmit}>
+               <Modal.Body>
+                       <Row>
+                               <Form.Group as={Col} sm={3} controlId="snes.proto">
+                                       <Form.Label>{t('snes.proto')}</Form.Label>
+                                       <Form.Select
+                                               isInvalid={!!(touched.proto && errors.proto)}
+                                               name="proto"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               value={values.proto || 'ws'}
+                                       >
+                                               <option value="ws">ws://</option>
+                                               <option value="wss">wss://</option>
+                                       </Form.Select>
+                                       {touched.proto && errors.proto ?
+                                               <Form.Control.Feedback type="invalid">
+                                                       {t(errors.proto)}
+                                               </Form.Control.Feedback>
+                                       : null}
+                               </Form.Group>
+                               <Form.Group as={Col} sm={6} controlId="snes.host">
+                                       <Form.Label>{t('snes.host')}</Form.Label>
+                                       <Form.Control
+                                               isInvalid={!!(touched.host && errors.host)}
+                                               name="host"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               type="text"
+                                               value={values.host || 'localhost'}
+                                       />
+                                       {touched.host && errors.host ?
+                                               <Form.Control.Feedback type="invalid">
+                                                       {t(errors.host)}
+                                               </Form.Control.Feedback>
+                                       : null}
+                               </Form.Group>
+                               <Form.Group as={Col} sm={3} controlId="snes.port">
+                                       <Form.Label>{t('snes.port')}</Form.Label>
+                                       <Form.Control
+                                               isInvalid={!!(touched.port && errors.port)}
+                                               min="1"
+                                               max="65665"
+                                               name="port"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               type="number"
+                                               value={values.port || 8080}
+                                       />
+                                       {touched.port && errors.port ?
+                                               <Form.Control.Feedback type="invalid">
+                                                       {t(errors.port)}
+                                               </Form.Control.Feedback>
+                                       : null}
+                               </Form.Group>
+                               <Form.Group as={Col} sm={12} controlId="snes.device">
+                                       <Form.Label>{t('snes.device')}</Form.Label>
+                                       <Form.Select
+                                               isInvalid={!!(touched.device && errors.device)}
+                                               name="device"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               value={values.device || ''}
+                                       >
+                                               <option value="">Auto</option>
+                                               {settings.device && !deviceList.includes(settings.device) ?
+                                                       <option value={settings.device}>{settings.device}</option>
+                                               : null}
+                                               {deviceList.map(device =>
+                                                       <option key={device} value={device}>{device}</option>
+                                               )}
+                                       </Form.Select>
+                                       {touched.device && errors.device ?
+                                               <Form.Control.Feedback type="invalid">
+                                                       {t(errors.device)}
+                                               </Form.Control.Feedback>
+                                       : null}
+                               </Form.Group>
+                       </Row>
+               </Modal.Body>
+               <Modal.Footer>
+                       {onCancel ?
+                               <Button onClick={onCancel} variant="secondary">
+                                       {t('button.cancel')}
+                               </Button>
+                       : null}
+                       <Button type="submit" variant="primary">
+                               {t('button.save')}
+                       </Button>
+               </Modal.Footer>
+       </Form>;
+};
+
+SettingsForm.propTypes = {
+       deviceList: PropTypes.arrayOf(PropTypes.string),
+       errors: PropTypes.shape({
+               device: PropTypes.string,
+               host: PropTypes.string,
+               port: PropTypes.string,
+               proto: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       settings: PropTypes.shape({
+               device: PropTypes.string,
+               host: PropTypes.string,
+               port: PropTypes.number,
+               proto: PropTypes.string,
+       }),
+       touched: PropTypes.shape({
+               device: PropTypes.bool,
+               host: PropTypes.bool,
+               port: PropTypes.bool,
+               proto: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               device: PropTypes.string,
+               host: PropTypes.string,
+               port: PropTypes.number,
+               proto: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'SettingsForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { onSubmit } = actions.props;
+               onSubmit(values);
+       },
+       mapPropsToValues: ({ settings }) => settings,
+       validationSchema: yup.object().shape({
+               device: yup.string(),
+               host: yup.string(),
+               port: yup.number().min(1).max(65665),
+               proto: yup.string(),
+       }),
+})(SettingsForm);
diff --git a/resources/js/components/techniques/Detail.js b/resources/js/components/techniques/Detail.js
deleted file mode 100644 (file)
index 376a391..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Button, Container } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import List from './List';
-import Outline from './Outline';
-import Requirements from './Requirements';
-import Rulesets from './Rulesets';
-import Icon from '../common/Icon';
-import RawHTML from '../common/RawHTML';
-import nl2br from '../../helpers/nl2br';
-import {
-       getRelations,
-       getTranslation,
-       hasRelations,
-       sorted,
-} from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const Detail = ({ actions, technique }) => {
-       const { t } = useTranslation();
-
-       return <Container as="article">
-               <div className="d-flex align-items-center justify-content-between">
-                       <h1>
-                               {getTranslation(technique, 'title', i18n.language)}
-                               {actions.editContent ?
-                                       <Button
-                                               className="ms-3"
-                                               onClick={() => actions.editContent(technique)}
-                                               size="sm"
-                                               title={t('button.edit')}
-                                               variant="outline-secondary"
-                                       >
-                                               <Icon.EDIT title="" />
-                                       </Button>
-                               : null}
-                       </h1>
-                       {technique && technique.rulesets ?
-                               <Rulesets technique={technique} />
-                       : null}
-               </div>
-               <Outline technique={technique} />
-               <Requirements technique={technique} />
-               <RawHTML html={getTranslation(technique, 'description', i18n.language)} />
-               {technique.chapters ? technique.chapters.map(chapter =>
-                       <section id={`c${chapter.id}`} key={`c${chapter.id}`}>
-                               {chapter.pivot.level ?
-                                       React.createElement(
-                                               `h${chapter.pivot.level}`,
-                                               {},
-                                               getTranslation(chapter, 'title', i18n.language),
-                                               actions.editContent ?
-                                                       <Button
-                                                               className="ms-3"
-                                                               onClick={() => actions.editContent(chapter)}
-                                                               size="sm"
-                                                               title={t('button.edit')}
-                                                               variant="outline-secondary"
-                                                       >
-                                                               <Icon.EDIT title="" />
-                                                       </Button>
-                                               : null,
-                                       )
-                               : null}
-                               <RawHTML html={getTranslation(chapter, 'description', i18n.language)} />
-                       </section>
-               ) : null}
-               {hasRelations(technique, 'related') ? <>
-                       <h2 className="mt-5">{i18n.t('techniques.seeAlso')}</h2>
-                       <List techniques={sorted(getRelations(technique, 'related'))} />
-               </> : null}
-               {getTranslation(technique, 'attribution', i18n.language) ?
-                       <Alert variant="dark">
-                               {nl2br(getTranslation(technique, 'attribution', i18n.language))}
-                       </Alert>
-               : null}
-       </Container>;
-};
-
-Detail.propTypes = {
-       actions: PropTypes.shape({
-               editContent: PropTypes.func,
-       }),
-       technique: PropTypes.shape({
-               chapters: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               description: PropTypes.string,
-               rulesets: PropTypes.shape({
-               }),
-               title: PropTypes.string,
-       }),
-};
-
-export default Detail;
diff --git a/resources/js/components/techniques/Detail.jsx b/resources/js/components/techniques/Detail.jsx
new file mode 100644 (file)
index 0000000..376a391
--- /dev/null
@@ -0,0 +1,96 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, Container } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import List from './List';
+import Outline from './Outline';
+import Requirements from './Requirements';
+import Rulesets from './Rulesets';
+import Icon from '../common/Icon';
+import RawHTML from '../common/RawHTML';
+import nl2br from '../../helpers/nl2br';
+import {
+       getRelations,
+       getTranslation,
+       hasRelations,
+       sorted,
+} from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const Detail = ({ actions, technique }) => {
+       const { t } = useTranslation();
+
+       return <Container as="article">
+               <div className="d-flex align-items-center justify-content-between">
+                       <h1>
+                               {getTranslation(technique, 'title', i18n.language)}
+                               {actions.editContent ?
+                                       <Button
+                                               className="ms-3"
+                                               onClick={() => actions.editContent(technique)}
+                                               size="sm"
+                                               title={t('button.edit')}
+                                               variant="outline-secondary"
+                                       >
+                                               <Icon.EDIT title="" />
+                                       </Button>
+                               : null}
+                       </h1>
+                       {technique && technique.rulesets ?
+                               <Rulesets technique={technique} />
+                       : null}
+               </div>
+               <Outline technique={technique} />
+               <Requirements technique={technique} />
+               <RawHTML html={getTranslation(technique, 'description', i18n.language)} />
+               {technique.chapters ? technique.chapters.map(chapter =>
+                       <section id={`c${chapter.id}`} key={`c${chapter.id}`}>
+                               {chapter.pivot.level ?
+                                       React.createElement(
+                                               `h${chapter.pivot.level}`,
+                                               {},
+                                               getTranslation(chapter, 'title', i18n.language),
+                                               actions.editContent ?
+                                                       <Button
+                                                               className="ms-3"
+                                                               onClick={() => actions.editContent(chapter)}
+                                                               size="sm"
+                                                               title={t('button.edit')}
+                                                               variant="outline-secondary"
+                                                       >
+                                                               <Icon.EDIT title="" />
+                                                       </Button>
+                                               : null,
+                                       )
+                               : null}
+                               <RawHTML html={getTranslation(chapter, 'description', i18n.language)} />
+                       </section>
+               ) : null}
+               {hasRelations(technique, 'related') ? <>
+                       <h2 className="mt-5">{i18n.t('techniques.seeAlso')}</h2>
+                       <List techniques={sorted(getRelations(technique, 'related'))} />
+               </> : null}
+               {getTranslation(technique, 'attribution', i18n.language) ?
+                       <Alert variant="dark">
+                               {nl2br(getTranslation(technique, 'attribution', i18n.language))}
+                       </Alert>
+               : null}
+       </Container>;
+};
+
+Detail.propTypes = {
+       actions: PropTypes.shape({
+               editContent: PropTypes.func,
+       }),
+       technique: PropTypes.shape({
+               chapters: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               description: PropTypes.string,
+               rulesets: PropTypes.shape({
+               }),
+               title: PropTypes.string,
+       }),
+};
+
+export default Detail;
diff --git a/resources/js/components/techniques/Dialog.js b/resources/js/components/techniques/Dialog.js
deleted file mode 100644 (file)
index eefa9d7..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Loading from '../common/Loading';
-import LanguageSwitcher from '../../app/LanguageSwitcher';
-
-const Form = React.lazy(() => import('./Form'));
-
-const Dialog = ({
-       content,
-       language,
-       onHide,
-       onSubmit,
-       show,
-}) => {
-       const { t } = useTranslation();
-
-       return <Modal onHide={onHide} show={show} size="lg">
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {t('content.edit')}
-                       </Modal.Title>
-                       <div className="mx-3">
-                               <LanguageSwitcher />
-                       </div>
-               </Modal.Header>
-               <React.Suspense fallback={<Loading />}>
-                       <Form
-                               content={content}
-                               language={language}
-                               onCancel={onHide}
-                               onSubmit={onSubmit}
-                       />
-               </React.Suspense>
-       </Modal>;
-};
-
-Dialog.propTypes = {
-       content: PropTypes.shape({
-       }),
-       language: PropTypes.string,
-       onHide: PropTypes.func,
-       onSubmit: PropTypes.func,
-       show: PropTypes.bool,
-};
-
-export default Dialog;
diff --git a/resources/js/components/techniques/Dialog.jsx b/resources/js/components/techniques/Dialog.jsx
new file mode 100644 (file)
index 0000000..eefa9d7
--- /dev/null
@@ -0,0 +1,49 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Loading from '../common/Loading';
+import LanguageSwitcher from '../../app/LanguageSwitcher';
+
+const Form = React.lazy(() => import('./Form'));
+
+const Dialog = ({
+       content,
+       language,
+       onHide,
+       onSubmit,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal onHide={onHide} show={show} size="lg">
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('content.edit')}
+                       </Modal.Title>
+                       <div className="mx-3">
+                               <LanguageSwitcher />
+                       </div>
+               </Modal.Header>
+               <React.Suspense fallback={<Loading />}>
+                       <Form
+                               content={content}
+                               language={language}
+                               onCancel={onHide}
+                               onSubmit={onSubmit}
+                       />
+               </React.Suspense>
+       </Modal>;
+};
+
+Dialog.propTypes = {
+       content: PropTypes.shape({
+       }),
+       language: PropTypes.string,
+       onHide: PropTypes.func,
+       onSubmit: PropTypes.func,
+       show: PropTypes.bool,
+};
+
+export default Dialog;
diff --git a/resources/js/components/techniques/Form.js b/resources/js/components/techniques/Form.js
deleted file mode 100644 (file)
index b6dd3d5..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import HTMLInput from '../common/HTMLInput';
-import { getTranslation } from '../../helpers/Technique';
-import yup from '../../schema/yup';
-
-const ContentForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       touched,
-       values,
-}) => {
-       const { t } = useTranslation();
-
-       return <Form noValidate onSubmit={handleSubmit}>
-               <Modal.Body>
-                       <Row>
-                               <Form.Group as={Col} md={6} controlId="content.title">
-                                       <Form.Label>{t('content.title')}</Form.Label>
-                                       <Form.Control
-                                               isInvalid={!!(touched.title && errors.title)}
-                                               name="title"
-                                               onBlur={handleBlur}
-                                               onChange={handleChange}
-                                               type="text"
-                                               value={values.title || ''}
-                                       />
-                               </Form.Group>
-                       </Row>
-                       <Form.Group controlId="content.short">
-                               <Form.Label>{t('content.short')}</Form.Label>
-                               <Form.Control
-                                       as="textarea"
-                                       isInvalid={!!(touched.short && errors.short)}
-                                       name="short"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       rows={3}
-                                       value={values.short || ''}
-                               />
-                       </Form.Group>
-                       <Form.Group controlId="content.description">
-                               <Form.Label>{t('content.description')}</Form.Label>
-                               <Form.Control
-                                       as={HTMLInput}
-                                       isInvalid={!!(touched.description && errors.description)}
-                                       name="description"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       rows={10}
-                                       value={values.description || ''}
-                               />
-                       </Form.Group>
-                       <Form.Group controlId="content.attribution">
-                               <Form.Label>{t('content.attribution')}</Form.Label>
-                               <Form.Control
-                                       as="textarea"
-                                       isInvalid={!!(touched.attribution && errors.attribution)}
-                                       name="attribution"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       rows={3}
-                                       value={values.attribution || ''}
-                               />
-                       </Form.Group>
-               </Modal.Body>
-               <Modal.Footer>
-                       {onCancel ?
-                               <Button onClick={onCancel} variant="secondary">
-                                       {t('button.cancel')}
-                               </Button>
-                       : null}
-                       <Button type="submit" variant="primary">
-                               {t('button.save')}
-                       </Button>
-               </Modal.Footer>
-       </Form>;
-};
-
-ContentForm.propTypes = {
-       errors: PropTypes.shape({
-               attribution: PropTypes.string,
-               description: PropTypes.string,
-               short: PropTypes.string,
-               title: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               attribution: PropTypes.bool,
-               description: PropTypes.bool,
-               short: PropTypes.bool,
-               title: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               attribution: PropTypes.string,
-               description: PropTypes.string,
-               short: PropTypes.string,
-               title: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'ContentForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { onSubmit } = actions.props;
-               await onSubmit(values);
-       },
-       mapPropsToValues: ({ content, language }) => ({
-               attribution: getTranslation(content, 'attribution', language),
-               description: getTranslation(content, 'description', language),
-               id: (content && content.id) || null,
-               language,
-               short: getTranslation(content, 'short', language),
-               title: getTranslation(content, 'title', language),
-       }),
-       validationSchema: yup.object().shape({
-               attribution: yup.string(),
-               description: yup.string(),
-               short: yup.string(),
-               title: yup.string(),
-       }),
-})(ContentForm);
diff --git a/resources/js/components/techniques/Form.jsx b/resources/js/components/techniques/Form.jsx
new file mode 100644 (file)
index 0000000..b6dd3d5
--- /dev/null
@@ -0,0 +1,133 @@
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import HTMLInput from '../common/HTMLInput';
+import { getTranslation } from '../../helpers/Technique';
+import yup from '../../schema/yup';
+
+const ContentForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       touched,
+       values,
+}) => {
+       const { t } = useTranslation();
+
+       return <Form noValidate onSubmit={handleSubmit}>
+               <Modal.Body>
+                       <Row>
+                               <Form.Group as={Col} md={6} controlId="content.title">
+                                       <Form.Label>{t('content.title')}</Form.Label>
+                                       <Form.Control
+                                               isInvalid={!!(touched.title && errors.title)}
+                                               name="title"
+                                               onBlur={handleBlur}
+                                               onChange={handleChange}
+                                               type="text"
+                                               value={values.title || ''}
+                                       />
+                               </Form.Group>
+                       </Row>
+                       <Form.Group controlId="content.short">
+                               <Form.Label>{t('content.short')}</Form.Label>
+                               <Form.Control
+                                       as="textarea"
+                                       isInvalid={!!(touched.short && errors.short)}
+                                       name="short"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       rows={3}
+                                       value={values.short || ''}
+                               />
+                       </Form.Group>
+                       <Form.Group controlId="content.description">
+                               <Form.Label>{t('content.description')}</Form.Label>
+                               <Form.Control
+                                       as={HTMLInput}
+                                       isInvalid={!!(touched.description && errors.description)}
+                                       name="description"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       rows={10}
+                                       value={values.description || ''}
+                               />
+                       </Form.Group>
+                       <Form.Group controlId="content.attribution">
+                               <Form.Label>{t('content.attribution')}</Form.Label>
+                               <Form.Control
+                                       as="textarea"
+                                       isInvalid={!!(touched.attribution && errors.attribution)}
+                                       name="attribution"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       rows={3}
+                                       value={values.attribution || ''}
+                               />
+                       </Form.Group>
+               </Modal.Body>
+               <Modal.Footer>
+                       {onCancel ?
+                               <Button onClick={onCancel} variant="secondary">
+                                       {t('button.cancel')}
+                               </Button>
+                       : null}
+                       <Button type="submit" variant="primary">
+                               {t('button.save')}
+                       </Button>
+               </Modal.Footer>
+       </Form>;
+};
+
+ContentForm.propTypes = {
+       errors: PropTypes.shape({
+               attribution: PropTypes.string,
+               description: PropTypes.string,
+               short: PropTypes.string,
+               title: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               attribution: PropTypes.bool,
+               description: PropTypes.bool,
+               short: PropTypes.bool,
+               title: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               attribution: PropTypes.string,
+               description: PropTypes.string,
+               short: PropTypes.string,
+               title: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'ContentForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { onSubmit } = actions.props;
+               await onSubmit(values);
+       },
+       mapPropsToValues: ({ content, language }) => ({
+               attribution: getTranslation(content, 'attribution', language),
+               description: getTranslation(content, 'description', language),
+               id: (content && content.id) || null,
+               language,
+               short: getTranslation(content, 'short', language),
+               title: getTranslation(content, 'title', language),
+       }),
+       validationSchema: yup.object().shape({
+               attribution: yup.string(),
+               description: yup.string(),
+               short: yup.string(),
+               title: yup.string(),
+       }),
+})(ContentForm);
diff --git a/resources/js/components/techniques/List.js b/resources/js/components/techniques/List.js
deleted file mode 100644 (file)
index aa80836..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Link } from 'react-router-dom';
-
-import Rulesets from './Rulesets';
-import {
-       getLink,
-       getTranslation,
-} from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const List = ({ techniques }) => <ul className="tech-list">
-       {techniques.map(tech =>
-               <li className="d-flex align-items-start justify-content-between" key={tech.id}>
-                       <div>
-                               <h2>
-                                       <Link to={getLink(tech)}>
-                                               {getTranslation(tech, 'title', i18n.language)}
-                                       </Link>
-                               </h2>
-                               <p>{getTranslation(tech, 'short', i18n.language)}</p>
-                       </div>
-                       {tech.rulesets ?
-                               <Rulesets technique={tech} />
-                       : null}
-               </li>
-       )}
-</ul>;
-
-List.propTypes = {
-       techniques: PropTypes.arrayOf(PropTypes.shape({
-               id: PropTypes.number,
-               name: PropTypes.string,
-       })),
-};
-
-export default List;
diff --git a/resources/js/components/techniques/List.jsx b/resources/js/components/techniques/List.jsx
new file mode 100644 (file)
index 0000000..aa80836
--- /dev/null
@@ -0,0 +1,37 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Link } from 'react-router-dom';
+
+import Rulesets from './Rulesets';
+import {
+       getLink,
+       getTranslation,
+} from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const List = ({ techniques }) => <ul className="tech-list">
+       {techniques.map(tech =>
+               <li className="d-flex align-items-start justify-content-between" key={tech.id}>
+                       <div>
+                               <h2>
+                                       <Link to={getLink(tech)}>
+                                               {getTranslation(tech, 'title', i18n.language)}
+                                       </Link>
+                               </h2>
+                               <p>{getTranslation(tech, 'short', i18n.language)}</p>
+                       </div>
+                       {tech.rulesets ?
+                               <Rulesets technique={tech} />
+                       : null}
+               </li>
+       )}
+</ul>;
+
+List.propTypes = {
+       techniques: PropTypes.arrayOf(PropTypes.shape({
+               id: PropTypes.number,
+               name: PropTypes.string,
+       })),
+};
+
+export default List;
diff --git a/resources/js/components/techniques/Outline.js b/resources/js/components/techniques/Outline.js
deleted file mode 100644 (file)
index ae18aa8..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { ListGroup } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import { getTranslation } from '../../helpers/Technique';
-import i18n from '../../i18n';
-
-const Outline = ({ technique }) => technique.chapters && technique.chapters.length ?
-       <aside className="tech-outline mb-3 ms-3">
-               <ListGroup>
-                       {technique.chapters.map(chapter => chapter.pivot.level ?
-                               <ListGroup.Item
-                                       action
-                                       href={`#c${chapter.id}`}
-                                       key={`c${chapter.id}`}
-                                       title={getTranslation(chapter, 'short', i18n.language) || null}
-                               >
-                                       {getTranslation(chapter, 'title', i18n.language)}
-                               </ListGroup.Item>
-                       : null)}
-               </ListGroup>
-       </aside>
-: null;
-
-Outline.propTypes = {
-       technique: PropTypes.shape({
-               chapters: PropTypes.arrayOf(PropTypes.shape({
-               })),
-       }),
-};
-
-export default withTranslation()(Outline);
diff --git a/resources/js/components/techniques/Outline.jsx b/resources/js/components/techniques/Outline.jsx
new file mode 100644 (file)
index 0000000..ae18aa8
--- /dev/null
@@ -0,0 +1,33 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { ListGroup } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import { getTranslation } from '../../helpers/Technique';
+import i18n from '../../i18n';
+
+const Outline = ({ technique }) => technique.chapters && technique.chapters.length ?
+       <aside className="tech-outline mb-3 ms-3">
+               <ListGroup>
+                       {technique.chapters.map(chapter => chapter.pivot.level ?
+                               <ListGroup.Item
+                                       action
+                                       href={`#c${chapter.id}`}
+                                       key={`c${chapter.id}`}
+                                       title={getTranslation(chapter, 'short', i18n.language) || null}
+                               >
+                                       {getTranslation(chapter, 'title', i18n.language)}
+                               </ListGroup.Item>
+                       : null)}
+               </ListGroup>
+       </aside>
+: null;
+
+Outline.propTypes = {
+       technique: PropTypes.shape({
+               chapters: PropTypes.arrayOf(PropTypes.shape({
+               })),
+       }),
+};
+
+export default withTranslation()(Outline);
diff --git a/resources/js/components/techniques/Overview.js b/resources/js/components/techniques/Overview.js
deleted file mode 100644 (file)
index f82a877..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Container } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import List from './List';
-import TechFilter from './TechFilter';
-import i18n from '../../i18n';
-
-const Overview = ({
-       filter,
-       namespace,
-       setFilter,
-       techniques,
-       type,
-}) => <Container>
-       <div className="d-flex align-items-center justify-content-between">
-               <h1>{i18n.t(`${namespace}.heading`)}</h1>
-               {type === 'tech' ?
-                       <TechFilter filter={filter} setFilter={setFilter} />
-               : null}
-       </div>
-       <List techniques={techniques} />
-</Container>;
-
-Overview.propTypes = {
-       filter: PropTypes.shape({}),
-       namespace: PropTypes.string,
-       setFilter: PropTypes.func,
-       techniques: PropTypes.arrayOf(PropTypes.shape({
-       })),
-       type: PropTypes.string,
-};
-
-export default withTranslation()(Overview);
diff --git a/resources/js/components/techniques/Overview.jsx b/resources/js/components/techniques/Overview.jsx
new file mode 100644 (file)
index 0000000..f82a877
--- /dev/null
@@ -0,0 +1,35 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Container } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import List from './List';
+import TechFilter from './TechFilter';
+import i18n from '../../i18n';
+
+const Overview = ({
+       filter,
+       namespace,
+       setFilter,
+       techniques,
+       type,
+}) => <Container>
+       <div className="d-flex align-items-center justify-content-between">
+               <h1>{i18n.t(`${namespace}.heading`)}</h1>
+               {type === 'tech' ?
+                       <TechFilter filter={filter} setFilter={setFilter} />
+               : null}
+       </div>
+       <List techniques={techniques} />
+</Container>;
+
+Overview.propTypes = {
+       filter: PropTypes.shape({}),
+       namespace: PropTypes.string,
+       setFilter: PropTypes.func,
+       techniques: PropTypes.arrayOf(PropTypes.shape({
+       })),
+       type: PropTypes.string,
+};
+
+export default withTranslation()(Overview);
diff --git a/resources/js/components/techniques/Requirement.js b/resources/js/components/techniques/Requirement.js
deleted file mode 100644 (file)
index 5faa372..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import ZeldaIcon from '../common/ZeldaIcon';
-
-const Requirement = ({ requirement }) =>
-       <div className="requirement">
-               {requirement.map(r =>
-                       <ZeldaIcon key={r} name={r} />
-               )}
-       </div>;
-
-Requirement.propTypes = {
-       requirement: PropTypes.arrayOf(PropTypes.string),
-};
-
-export default Requirement;
diff --git a/resources/js/components/techniques/Requirement.jsx b/resources/js/components/techniques/Requirement.jsx
new file mode 100644 (file)
index 0000000..5faa372
--- /dev/null
@@ -0,0 +1,17 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import ZeldaIcon from '../common/ZeldaIcon';
+
+const Requirement = ({ requirement }) =>
+       <div className="requirement">
+               {requirement.map(r =>
+                       <ZeldaIcon key={r} name={r} />
+               )}
+       </div>;
+
+Requirement.propTypes = {
+       requirement: PropTypes.arrayOf(PropTypes.string),
+};
+
+export default Requirement;
diff --git a/resources/js/components/techniques/Requirements.js b/resources/js/components/techniques/Requirements.js
deleted file mode 100644 (file)
index 7919b58..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-import Requirement from './Requirement';
-
-const Requirements = ({ technique }) => {
-       const { t } = useTranslation();
-
-       if (!technique.requirements || !technique.requirements.length) {
-               return null;
-       }
-
-       return <div className="tech-requirements mb-3">
-               {t('techniques.requirements')}
-               <ul>
-                       {technique.requirements.map((r, i) =>
-                               <li key={i}>
-                                       <Requirement requirement={r} />
-                               </li>
-                       )}
-               </ul>
-       </div>;
-};
-
-Requirements.propTypes = {
-       technique: PropTypes.shape({
-               requirements: PropTypes.arrayOf(
-                       PropTypes.arrayOf(PropTypes.string),
-               ),
-       }),
-};
-
-export default Requirements;
diff --git a/resources/js/components/techniques/Requirements.jsx b/resources/js/components/techniques/Requirements.jsx
new file mode 100644 (file)
index 0000000..7919b58
--- /dev/null
@@ -0,0 +1,34 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import Requirement from './Requirement';
+
+const Requirements = ({ technique }) => {
+       const { t } = useTranslation();
+
+       if (!technique.requirements || !technique.requirements.length) {
+               return null;
+       }
+
+       return <div className="tech-requirements mb-3">
+               {t('techniques.requirements')}
+               <ul>
+                       {technique.requirements.map((r, i) =>
+                               <li key={i}>
+                                       <Requirement requirement={r} />
+                               </li>
+                       )}
+               </ul>
+       </div>;
+};
+
+Requirements.propTypes = {
+       technique: PropTypes.shape({
+               requirements: PropTypes.arrayOf(
+                       PropTypes.arrayOf(PropTypes.string),
+               ),
+       }),
+};
+
+export default Requirements;
diff --git a/resources/js/components/techniques/Rulesets.js b/resources/js/components/techniques/Rulesets.js
deleted file mode 100644 (file)
index 6d4ee50..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-import Icon from '../common/Icon';
-
-const Rulesets = ({ technique }) => {
-       const { t } = useTranslation();
-
-       return <div className="ruleset-box">
-               {['competitive', 'owg', 'mg', 'nl'].map(r =>
-                       <span key={r} title={t(`techniques.rulesetDescriptions.${r}`)}>
-                               {technique && technique.rulesets && technique.rulesets[r] ?
-                                       <Icon.ALLOWED className="text-success" />
-                               : null}
-                               {technique && technique.rulesets && !technique.rulesets[r] ?
-                                       <Icon.FORBIDDEN className="text-danger" />
-                               : null}
-                               {!technique || !technique.rulesets ?
-                                       <Icon.UNKNOWN />
-                               : null}
-                               {' '}
-                               {t(`techniques.rulesetCodes.${r}`)}
-                       </span>
-               )}
-       </div>;
-};
-
-Rulesets.propTypes = {
-       technique: PropTypes.shape({
-               rulesets: PropTypes.shape({
-               }),
-       }),
-};
-
-export default Rulesets;
diff --git a/resources/js/components/techniques/Rulesets.jsx b/resources/js/components/techniques/Rulesets.jsx
new file mode 100644 (file)
index 0000000..6d4ee50
--- /dev/null
@@ -0,0 +1,36 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../common/Icon';
+
+const Rulesets = ({ technique }) => {
+       const { t } = useTranslation();
+
+       return <div className="ruleset-box">
+               {['competitive', 'owg', 'mg', 'nl'].map(r =>
+                       <span key={r} title={t(`techniques.rulesetDescriptions.${r}`)}>
+                               {technique && technique.rulesets && technique.rulesets[r] ?
+                                       <Icon.ALLOWED className="text-success" />
+                               : null}
+                               {technique && technique.rulesets && !technique.rulesets[r] ?
+                                       <Icon.FORBIDDEN className="text-danger" />
+                               : null}
+                               {!technique || !technique.rulesets ?
+                                       <Icon.UNKNOWN />
+                               : null}
+                               {' '}
+                               {t(`techniques.rulesetCodes.${r}`)}
+                       </span>
+               )}
+       </div>;
+};
+
+Rulesets.propTypes = {
+       technique: PropTypes.shape({
+               rulesets: PropTypes.shape({
+               }),
+       }),
+};
+
+export default Rulesets;
diff --git a/resources/js/components/techniques/TechFilter.js b/resources/js/components/techniques/TechFilter.js
deleted file mode 100644 (file)
index 008288a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Form } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-const TechFilter = ({ filter, setFilter }) => {
-       const { t } = useTranslation();
-
-       const handleChange = React.useCallback(e => {
-               if (e.target.name.startsWith('ruleset.')) {
-                       const r = e.target.name.substring(8);
-                       setFilter({
-                               ...filter,
-                               ruleset: {
-                                       ...filter.ruleset || {},
-                                       [r]: e.target.checked ? '1' : '0',
-                               },
-                       });
-               }
-       }, [filter]);
-
-       return <div className="tech-filter">
-               <div>{t('techniques.rulesetFilterHeading')}</div>
-               <div className="ruleset-box">
-                       {['competitive', 'owg', 'mg', 'nl'].map(r =>
-                               <Form.Check
-                                       checked={!!(filter && filter.ruleset && filter.ruleset[r] === '1')}
-                                       key={r}
-                                       id={`tech.filter.ruleset.${r}`}
-                                       name={`ruleset.${r}`}
-                                       label={t(`techniques.rulesetCodes.${r}`)}
-                                       onChange={handleChange}
-                                       title={t(`techniques.rulesetDescriptions.${r}`)}
-                                       type="checkbox"
-                               />
-                       )}
-               </div>
-       </div>;
-};
-
-TechFilter.propTypes = {
-       filter: PropTypes.shape({
-               ruleset: PropTypes.shape({
-               }),
-       }),
-       setFilter: PropTypes.func,
-};
-
-export default TechFilter;
diff --git a/resources/js/components/techniques/TechFilter.jsx b/resources/js/components/techniques/TechFilter.jsx
new file mode 100644 (file)
index 0000000..008288a
--- /dev/null
@@ -0,0 +1,49 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Form } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const TechFilter = ({ filter, setFilter }) => {
+       const { t } = useTranslation();
+
+       const handleChange = React.useCallback(e => {
+               if (e.target.name.startsWith('ruleset.')) {
+                       const r = e.target.name.substring(8);
+                       setFilter({
+                               ...filter,
+                               ruleset: {
+                                       ...filter.ruleset || {},
+                                       [r]: e.target.checked ? '1' : '0',
+                               },
+                       });
+               }
+       }, [filter]);
+
+       return <div className="tech-filter">
+               <div>{t('techniques.rulesetFilterHeading')}</div>
+               <div className="ruleset-box">
+                       {['competitive', 'owg', 'mg', 'nl'].map(r =>
+                               <Form.Check
+                                       checked={!!(filter && filter.ruleset && filter.ruleset[r] === '1')}
+                                       key={r}
+                                       id={`tech.filter.ruleset.${r}`}
+                                       name={`ruleset.${r}`}
+                                       label={t(`techniques.rulesetCodes.${r}`)}
+                                       onChange={handleChange}
+                                       title={t(`techniques.rulesetDescriptions.${r}`)}
+                                       type="checkbox"
+                               />
+                       )}
+               </div>
+       </div>;
+};
+
+TechFilter.propTypes = {
+       filter: PropTypes.shape({
+               ruleset: PropTypes.shape({
+               }),
+       }),
+       setFilter: PropTypes.func,
+};
+
+export default TechFilter;
diff --git a/resources/js/components/tournament/ApplyButton.js b/resources/js/components/tournament/ApplyButton.js
deleted file mode 100644 (file)
index 8bbd98e..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import Icon from '../common/Icon';
-import { isApplicant, isDeniedApplicant, isRunner, mayApply } from '../../helpers/permissions';
-import { useUser } from '../../hooks/user';
-import i18n from '../../i18n';
-
-const apply = async tournament => {
-       try {
-               await axios.post(`/api/tournaments/${tournament.id}/apply`);
-               toastr.success(i18n.t('tournaments.applySuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('tournaments.applyError'));
-       }
-};
-
-const getTitle = (user, tournament) => {
-       if (isDeniedApplicant(user, tournament)) {
-               return i18n.t('tournaments.applicationDenied');
-       }
-       if (isApplicant(user, tournament)) {
-               return i18n.t('tournaments.applicationPending');
-       }
-       return i18n.t('tournaments.apply');
-};
-
-const ApplyButton = ({ tournament }) => {
-       const { user } = useUser();
-
-       if (!user || !tournament.accept_applications || isRunner(user, tournament)) return null;
-
-       return <span className="d-inline-block" title={getTitle(user, tournament)}>
-               <Button
-                       disabled={!mayApply(user, tournament)}
-                       onClick={() => apply(tournament)}
-                       variant="primary"
-               >
-                       <Icon.APPLY title="" />
-               </Button>
-       </span>;
-};
-
-ApplyButton.propTypes = {
-       tournament: PropTypes.shape({
-               accept_applications: PropTypes.bool,
-               id: PropTypes.number,
-       }),
-};
-
-export default withTranslation()(ApplyButton);
diff --git a/resources/js/components/tournament/ApplyButton.jsx b/resources/js/components/tournament/ApplyButton.jsx
new file mode 100644 (file)
index 0000000..8bbd98e
--- /dev/null
@@ -0,0 +1,55 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import Icon from '../common/Icon';
+import { isApplicant, isDeniedApplicant, isRunner, mayApply } from '../../helpers/permissions';
+import { useUser } from '../../hooks/user';
+import i18n from '../../i18n';
+
+const apply = async tournament => {
+       try {
+               await axios.post(`/api/tournaments/${tournament.id}/apply`);
+               toastr.success(i18n.t('tournaments.applySuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('tournaments.applyError'));
+       }
+};
+
+const getTitle = (user, tournament) => {
+       if (isDeniedApplicant(user, tournament)) {
+               return i18n.t('tournaments.applicationDenied');
+       }
+       if (isApplicant(user, tournament)) {
+               return i18n.t('tournaments.applicationPending');
+       }
+       return i18n.t('tournaments.apply');
+};
+
+const ApplyButton = ({ tournament }) => {
+       const { user } = useUser();
+
+       if (!user || !tournament.accept_applications || isRunner(user, tournament)) return null;
+
+       return <span className="d-inline-block" title={getTitle(user, tournament)}>
+               <Button
+                       disabled={!mayApply(user, tournament)}
+                       onClick={() => apply(tournament)}
+                       variant="primary"
+               >
+                       <Icon.APPLY title="" />
+               </Button>
+       </span>;
+};
+
+ApplyButton.propTypes = {
+       tournament: PropTypes.shape({
+               accept_applications: PropTypes.bool,
+               id: PropTypes.number,
+       }),
+};
+
+export default withTranslation()(ApplyButton);
diff --git a/resources/js/components/tournament/Detail.js b/resources/js/components/tournament/Detail.js
deleted file mode 100644 (file)
index 318e677..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Container, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import ApplyButton from './ApplyButton';
-import Scoreboard from './Scoreboard';
-import ScoreChartButton from './ScoreChartButton';
-import SettingsButton from './SettingsButton';
-import ApplicationsButton from '../applications/Button';
-import Protocol from '../protocol/Protocol';
-import Rounds from '../rounds/List';
-import Box from '../users/Box';
-import {
-       isRunner,
-       mayAddRounds,
-       mayUpdateTournament,
-       mayViewProtocol,
-} from '../../helpers/permissions';
-import {
-       getTournamentAdmins,
-       getTournamentMonitors,
-       hasRunners,
-       hasScoreboard,
-       hasTournamentAdmins,
-       hasTournamentMonitors,
-} from '../../helpers/Tournament';
-import { useUser } from '../../hooks/user';
-
-const getClassName = (tournament, user) => {
-       const classNames = ['tournament'];
-       if (tournament.locked) {
-               classNames.push('is-locked');
-       } else {
-               classNames.push('is-active');
-       }
-       if (isRunner(user, tournament)) {
-               classNames.push('is-runner');
-       }
-       return classNames.join(' ');
-};
-
-const Detail = ({
-       addRound,
-       moreRounds,
-       tournament,
-}) => {
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       return <Container className={getClassName(tournament, user)} fluid>
-               <Row>
-                       <Col lg={8} xl={9}>
-                               <div className="d-flex align-items-center justify-content-between">
-                                       <h1>{tournament.title}</h1>
-                                       <div className="button-bar">
-                                               <ApplicationsButton tournament={tournament} />
-                                               <ApplyButton tournament={tournament} />
-                                               {mayUpdateTournament(user, tournament) ?
-                                                       <SettingsButton tournament={tournament} />
-                                               : null}
-                                               {mayViewProtocol(user, tournament) ?
-                                                       <Protocol id={tournament.id} />
-                                               : null}
-                                       </div>
-                               </div>
-                       </Col>
-               </Row>
-               <Row>
-                       <Col lg={{ order: 2, span: 4 }} xl={{ order: 2, span: 3 }}>
-                               <div className="tournament-sidebar">
-                                       {hasScoreboard(tournament) ? <>
-                                               <div className="d-flex align-items-center justify-content-between">
-                                                       <h2>{t('tournaments.scoreboard')}</h2>
-                                                       {hasRunners(tournament) && tournament.rounds.length > 2 ?
-                                                               <ScoreChartButton tournament={tournament} />
-                                                       : null}
-                                               </div>
-                                               {hasRunners(tournament) ?
-                                                       <Scoreboard tournament={tournament} />
-                                               : null}
-                                       </> : null}
-                                       {hasTournamentAdmins(tournament) ?
-                                               <>
-                                                       <div className="d-flex align-items-center justify-content-between">
-                                                               <h2>{t('tournaments.admins')}</h2>
-                                                       </div>
-                                                       {getTournamentAdmins(tournament).map(p =>
-                                                               <p key={p.id}><Box user={p.user} /></p>
-                                                       )}
-                                               </>
-                                       : null}
-                                       {hasTournamentMonitors(tournament) ?
-                                               <>
-                                                       <div className="d-flex align-items-center justify-content-between">
-                                                               <h2>{t('tournaments.monitors')}</h2>
-                                                       </div>
-                                                       {getTournamentMonitors(tournament).map(p =>
-                                                               <p key={p.id}><Box user={p.user} /></p>
-                                                       )}
-                                               </>
-                                       : null}
-                               </div>
-                       </Col>
-                       <Col lg={{ order: 1, span: 8 }} xl={{ order: 1, span: 9 }}>
-                               <div className="d-flex align-items-center justify-content-between">
-                                       <h2>{t('rounds.heading')}</h2>
-                                       {addRound && mayAddRounds(user, tournament) ?
-                                               <Button onClick={addRound}>
-                                                       {t('rounds.new')}
-                                               </Button>
-                                       : null}
-                               </div>
-                               {tournament.rounds ?
-                                       <Rounds
-                                               loadMore={moreRounds}
-                                               rounds={tournament.rounds}
-                                               tournament={tournament}
-                                       />
-                               : null}
-                       </Col>
-               </Row>
-       </Container>;
-};
-
-Detail.propTypes = {
-       addRound: PropTypes.func,
-       moreRounds: PropTypes.func,
-       tournament: PropTypes.shape({
-               id: PropTypes.number,
-               participants: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               rounds: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               title: PropTypes.string,
-       }),
-};
-
-export default Detail;
diff --git a/resources/js/components/tournament/Detail.jsx b/resources/js/components/tournament/Detail.jsx
new file mode 100644 (file)
index 0000000..a931865
--- /dev/null
@@ -0,0 +1,166 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Container, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import ApplyButton from './ApplyButton';
+import Scoreboard from './Scoreboard';
+import ScoreChartButton from './ScoreChartButton';
+import SettingsButton from './SettingsButton';
+import ApplicationsButton from '../applications/Button';
+import Icon from '../common/Icon';
+import RawHTML from '../common/RawHTML';
+import Protocol from '../protocol/Protocol';
+import Rounds from '../rounds/List';
+import Box from '../users/Box';
+import {
+       isRunner,
+       mayAddRounds,
+       mayUpdateTournament,
+       mayViewProtocol,
+} from '../../helpers/permissions';
+import { getTranslation } from '../../helpers/Technique';
+import {
+       getTournamentAdmins,
+       getTournamentMonitors,
+       hasRunners,
+       hasScoreboard,
+       hasTournamentAdmins,
+       hasTournamentMonitors,
+} from '../../helpers/Tournament';
+import { useUser } from '../../hooks/user';
+import i18n from '../../i18n';
+
+const getClassName = (tournament, user) => {
+       const classNames = ['tournament'];
+       if (tournament.locked) {
+               classNames.push('is-locked');
+       } else {
+               classNames.push('is-active');
+       }
+       if (isRunner(user, tournament)) {
+               classNames.push('is-runner');
+       }
+       return classNames.join(' ');
+};
+
+const Detail = ({
+       actions,
+       tournament,
+}) => {
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       return <Container className={getClassName(tournament, user)} fluid>
+               <Row>
+                       <Col lg={8} xl={9}>
+                               <div className="d-flex align-items-center justify-content-between">
+                                       <h1>
+                                               {(tournament.description
+                                                       && getTranslation(tournament.description, 'title', i18n.language))
+                                                       || tournament.title}
+                                       </h1>
+                                       <div className="button-bar">
+                                               {tournament.description && actions.editContent ?
+                                                       <Button
+                                                               className="ms-3"
+                                                               onClick={() => actions.editContent(tournament.description)}
+                                                               title={t('button.edit')}
+                                                               variant="outline-secondary"
+                                                       >
+                                                               <Icon.EDIT title="" />
+                                                       </Button>
+                                               : null}
+                                               <ApplicationsButton tournament={tournament} />
+                                               <ApplyButton tournament={tournament} />
+                                               {mayUpdateTournament(user, tournament) ?
+                                                       <SettingsButton tournament={tournament} />
+                                               : null}
+                                               {mayViewProtocol(user, tournament) ?
+                                                       <Protocol id={tournament.id} />
+                                               : null}
+                                       </div>
+                               </div>
+                               {tournament.description ?
+                                       <RawHTML
+                                               html={getTranslation(tournament.description, 'description', i18n.language)}
+                                       />
+                               : null}
+                       </Col>
+               </Row>
+               <Row>
+                       <Col lg={{ order: 2, span: 4 }} xl={{ order: 2, span: 3 }}>
+                               <div className="tournament-sidebar">
+                                       {hasScoreboard(tournament) ? <>
+                                               <div className="d-flex align-items-center justify-content-between">
+                                                       <h2>{t('tournaments.scoreboard')}</h2>
+                                                       {hasRunners(tournament) && tournament.rounds.length > 2 ?
+                                                               <ScoreChartButton tournament={tournament} />
+                                                       : null}
+                                               </div>
+                                               {hasRunners(tournament) ?
+                                                       <Scoreboard tournament={tournament} />
+                                               : null}
+                                       </> : null}
+                                       {hasTournamentAdmins(tournament) ?
+                                               <>
+                                                       <div className="d-flex align-items-center justify-content-between">
+                                                               <h2>{t('tournaments.admins')}</h2>
+                                                       </div>
+                                                       {getTournamentAdmins(tournament).map(p =>
+                                                               <p key={p.id}><Box user={p.user} /></p>
+                                                       )}
+                                               </>
+                                       : null}
+                                       {hasTournamentMonitors(tournament) ?
+                                               <>
+                                                       <div className="d-flex align-items-center justify-content-between">
+                                                               <h2>{t('tournaments.monitors')}</h2>
+                                                       </div>
+                                                       {getTournamentMonitors(tournament).map(p =>
+                                                               <p key={p.id}><Box user={p.user} /></p>
+                                                       )}
+                                               </>
+                                       : null}
+                               </div>
+                       </Col>
+                       <Col lg={{ order: 1, span: 8 }} xl={{ order: 1, span: 9 }}>
+                               <div className="d-flex align-items-center justify-content-between">
+                                       <h2>{t('rounds.heading')}</h2>
+                                       {actions.addRound && mayAddRounds(user, tournament) ?
+                                               <Button onClick={actions.addRound}>
+                                                       {t('rounds.new')}
+                                               </Button>
+                                       : null}
+                               </div>
+                               {tournament.rounds ?
+                                       <Rounds
+                                               loadMore={actions.moreRounds}
+                                               rounds={tournament.rounds}
+                                               tournament={tournament}
+                                       />
+                               : null}
+                       </Col>
+               </Row>
+       </Container>;
+};
+
+Detail.propTypes = {
+       actions: PropTypes.shape({
+               addRound: PropTypes.func,
+               editContent: PropTypes.func,
+               moreRounds: PropTypes.func,
+       }).isRequired,
+       tournament: PropTypes.shape({
+               description: PropTypes.shape({
+               }),
+               id: PropTypes.number,
+               participants: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               rounds: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               title: PropTypes.string,
+       }),
+};
+
+export default Detail;
diff --git a/resources/js/components/tournament/DiscordForm.js b/resources/js/components/tournament/DiscordForm.js
deleted file mode 100644 (file)
index d896504..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-import axios from 'axios';
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Form } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import DiscordChannelSelect from '../common/DiscordChannelSelect';
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import i18n from '../../i18n';
-import yup from '../../schema/yup';
-
-const DiscordForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       touched,
-       tournament,
-       values,
-}) =>
-<Form noValidate onSubmit={handleSubmit}>
-       <fieldset>
-               <legend>{i18n.t('tournaments.discordSettings')}</legend>
-               <Form.Group controlId="tournament.discord_round_category">
-                       <Form.Label>
-                               {i18n.t('tournaments.discordRoundCategory')}
-                       </Form.Label>
-                       <DiscordChannelSelect
-                               guild={tournament.discord}
-                               isInvalid={!!(touched.round_category && errors.round_category)}
-                               name="round_category"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               types={[4]}
-                               value={values.round_category || ''}
-                       />
-               </Form.Group>
-               <Form.Group controlId="tournament.discord_round_template">
-                       <Form.Label>
-                               {i18n.t('tournaments.discordRoundTemplate')}
-                       </Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.round_template && errors.round_template)}
-                               name="round_template"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.round_template || ''}
-                       />
-               </Form.Group>
-               <Button className="mt-3" type="submit" variant="primary">
-                       {i18n.t('button.save')}
-               </Button>
-       </fieldset>
-</Form>;
-
-DiscordForm.propTypes = {
-       errors: PropTypes.shape({
-               round_category: PropTypes.string,
-               round_template: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       touched: PropTypes.shape({
-               round_category: PropTypes.bool,
-               round_template: PropTypes.bool,
-       }),
-       tournament: PropTypes.shape({
-               discord: PropTypes.string,
-       }),
-       values: PropTypes.shape({
-               round_category: PropTypes.string,
-               round_template: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'DiscordForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { round_category, round_template } = values;
-               const { setErrors } = actions;
-               const { tournament } = actions.props;
-               try {
-                       await axios.post(`/api/tournaments/${tournament.id}/discord-settings`, {
-                               round_category,
-                               round_template,
-                       });
-                       toastr.success(i18n.t('tournaments.discordSettingsSuccess'));
-               } catch (e) {
-                       toastr.error(i18n.t('tournaments.discordSettingsError'));
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ tournament }) => ({
-               round_category: tournament.discord_round_category || '',
-               round_template: tournament.discord_round_template || '',
-       }),
-       validationSchema: yup.object().shape({
-               round_category: yup.string(),
-               round_template: yup.string(),
-       }),
-})(withTranslation()(DiscordForm));
diff --git a/resources/js/components/tournament/DiscordForm.jsx b/resources/js/components/tournament/DiscordForm.jsx
new file mode 100644 (file)
index 0000000..d896504
--- /dev/null
@@ -0,0 +1,108 @@
+import axios from 'axios';
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Form } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import DiscordChannelSelect from '../common/DiscordChannelSelect';
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import i18n from '../../i18n';
+import yup from '../../schema/yup';
+
+const DiscordForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       touched,
+       tournament,
+       values,
+}) =>
+<Form noValidate onSubmit={handleSubmit}>
+       <fieldset>
+               <legend>{i18n.t('tournaments.discordSettings')}</legend>
+               <Form.Group controlId="tournament.discord_round_category">
+                       <Form.Label>
+                               {i18n.t('tournaments.discordRoundCategory')}
+                       </Form.Label>
+                       <DiscordChannelSelect
+                               guild={tournament.discord}
+                               isInvalid={!!(touched.round_category && errors.round_category)}
+                               name="round_category"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               types={[4]}
+                               value={values.round_category || ''}
+                       />
+               </Form.Group>
+               <Form.Group controlId="tournament.discord_round_template">
+                       <Form.Label>
+                               {i18n.t('tournaments.discordRoundTemplate')}
+                       </Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.round_template && errors.round_template)}
+                               name="round_template"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.round_template || ''}
+                       />
+               </Form.Group>
+               <Button className="mt-3" type="submit" variant="primary">
+                       {i18n.t('button.save')}
+               </Button>
+       </fieldset>
+</Form>;
+
+DiscordForm.propTypes = {
+       errors: PropTypes.shape({
+               round_category: PropTypes.string,
+               round_template: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       touched: PropTypes.shape({
+               round_category: PropTypes.bool,
+               round_template: PropTypes.bool,
+       }),
+       tournament: PropTypes.shape({
+               discord: PropTypes.string,
+       }),
+       values: PropTypes.shape({
+               round_category: PropTypes.string,
+               round_template: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'DiscordForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { round_category, round_template } = values;
+               const { setErrors } = actions;
+               const { tournament } = actions.props;
+               try {
+                       await axios.post(`/api/tournaments/${tournament.id}/discord-settings`, {
+                               round_category,
+                               round_template,
+                       });
+                       toastr.success(i18n.t('tournaments.discordSettingsSuccess'));
+               } catch (e) {
+                       toastr.error(i18n.t('tournaments.discordSettingsError'));
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ tournament }) => ({
+               round_category: tournament.discord_round_category || '',
+               round_template: tournament.discord_round_template || '',
+       }),
+       validationSchema: yup.object().shape({
+               round_category: yup.string(),
+               round_template: yup.string(),
+       }),
+})(withTranslation()(DiscordForm));
diff --git a/resources/js/components/tournament/ScoreChart.js b/resources/js/components/tournament/ScoreChart.js
deleted file mode 100644 (file)
index b63c81e..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
-
-import { getUserName } from '../../helpers/Participant';
-import { getRunners, getScoreTable } from '../../helpers/Tournament';
-
-const COLORS = [
-       '#7cb5ec',
-       '#434348',
-       '#90ed7d',
-       '#f7a35c',
-       '#8085e9',
-       '#f15c80',
-       '#e4d354',
-       '#2b908f',
-       '#f45b5b',
-       '#91e8e1',
-];
-
-const ScoreChart = ({
-       tournament,
-}) =>
-<ResponsiveContainer height="100%" width="100%">
-       <LineChart data={getScoreTable(tournament)} height={720} width={1280}>
-               <XAxis dataKey="number" />
-               <YAxis />
-               <Tooltip />
-               <Legend />
-               {getRunners(tournament).map((runner, index) =>
-                       <Line
-                               dataKey={getUserName(runner)}
-                               key={runner.id}
-                               stroke={COLORS[index % COLORS.length]}
-                               type="monotone"
-                       />
-               )}
-       </LineChart>
-</ResponsiveContainer>;
-
-ScoreChart.propTypes = {
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default ScoreChart;
diff --git a/resources/js/components/tournament/ScoreChart.jsx b/resources/js/components/tournament/ScoreChart.jsx
new file mode 100644 (file)
index 0000000..b63c81e
--- /dev/null
@@ -0,0 +1,46 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Legend, Line, LineChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts';
+
+import { getUserName } from '../../helpers/Participant';
+import { getRunners, getScoreTable } from '../../helpers/Tournament';
+
+const COLORS = [
+       '#7cb5ec',
+       '#434348',
+       '#90ed7d',
+       '#f7a35c',
+       '#8085e9',
+       '#f15c80',
+       '#e4d354',
+       '#2b908f',
+       '#f45b5b',
+       '#91e8e1',
+];
+
+const ScoreChart = ({
+       tournament,
+}) =>
+<ResponsiveContainer height="100%" width="100%">
+       <LineChart data={getScoreTable(tournament)} height={720} width={1280}>
+               <XAxis dataKey="number" />
+               <YAxis />
+               <Tooltip />
+               <Legend />
+               {getRunners(tournament).map((runner, index) =>
+                       <Line
+                               dataKey={getUserName(runner)}
+                               key={runner.id}
+                               stroke={COLORS[index % COLORS.length]}
+                               type="monotone"
+                       />
+               )}
+       </LineChart>
+</ResponsiveContainer>;
+
+ScoreChart.propTypes = {
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default ScoreChart;
diff --git a/resources/js/components/tournament/ScoreChartButton.js b/resources/js/components/tournament/ScoreChartButton.js
deleted file mode 100644 (file)
index 9074487..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import ScoreChartDialog from './ScoreChartDialog';
-import Icon from '../common/Icon';
-import i18n from '../../i18n';
-
-const ScoreChartButton = ({ tournament }) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       return <>
-               <Button
-                       onClick={() => setShowDialog(true)}
-                       title={i18n.t('button.chart')}
-                       variant="info"
-               >
-                       <Icon.CHART title="" />
-               </Button>
-               <ScoreChartDialog
-                       onHide={() => setShowDialog(false)}
-                       tournament={tournament}
-                       show={showDialog}
-               />
-       </>;
-};
-
-ScoreChartButton.propTypes = {
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(ScoreChartButton);
diff --git a/resources/js/components/tournament/ScoreChartButton.jsx b/resources/js/components/tournament/ScoreChartButton.jsx
new file mode 100644 (file)
index 0000000..9074487
--- /dev/null
@@ -0,0 +1,34 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import ScoreChartDialog from './ScoreChartDialog';
+import Icon from '../common/Icon';
+import i18n from '../../i18n';
+
+const ScoreChartButton = ({ tournament }) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       return <>
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       title={i18n.t('button.chart')}
+                       variant="info"
+               >
+                       <Icon.CHART title="" />
+               </Button>
+               <ScoreChartDialog
+                       onHide={() => setShowDialog(false)}
+                       tournament={tournament}
+                       show={showDialog}
+               />
+       </>;
+};
+
+ScoreChartButton.propTypes = {
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(ScoreChartButton);
diff --git a/resources/js/components/tournament/ScoreChartDialog.js b/resources/js/components/tournament/ScoreChartDialog.js
deleted file mode 100644 (file)
index 2a04d1d..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import Loading from '../common/Loading';
-import i18n from '../../i18n';
-
-const ScoreChart = React.lazy(() => import('./ScoreChart'));
-
-const ScoreChartDialog = ({
-       onHide,
-       show,
-       tournament,
-}) =>
-<Modal className="score-chart-dialog" dialogClassName="modal-90w" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('tournaments.scoreChart')}
-               </Modal.Title>
-       </Modal.Header>
-       <Modal.Body style={{ height: '80vh' }}>
-               <React.Suspense fallback={<Loading />}>
-                       <ScoreChart tournament={tournament} />
-               </React.Suspense>
-       </Modal.Body>
-       <Modal.Footer>
-               <Button onClick={onHide} variant="secondary">
-                       {i18n.t('button.close')}
-               </Button>
-       </Modal.Footer>
-</Modal>;
-
-ScoreChartDialog.propTypes = {
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(ScoreChartDialog);
diff --git a/resources/js/components/tournament/ScoreChartDialog.jsx b/resources/js/components/tournament/ScoreChartDialog.jsx
new file mode 100644 (file)
index 0000000..2a04d1d
--- /dev/null
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import Loading from '../common/Loading';
+import i18n from '../../i18n';
+
+const ScoreChart = React.lazy(() => import('./ScoreChart'));
+
+const ScoreChartDialog = ({
+       onHide,
+       show,
+       tournament,
+}) =>
+<Modal className="score-chart-dialog" dialogClassName="modal-90w" onHide={onHide} show={show}>
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t('tournaments.scoreChart')}
+               </Modal.Title>
+       </Modal.Header>
+       <Modal.Body style={{ height: '80vh' }}>
+               <React.Suspense fallback={<Loading />}>
+                       <ScoreChart tournament={tournament} />
+               </React.Suspense>
+       </Modal.Body>
+       <Modal.Footer>
+               <Button onClick={onHide} variant="secondary">
+                       {i18n.t('button.close')}
+               </Button>
+       </Modal.Footer>
+</Modal>;
+
+ScoreChartDialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(ScoreChartDialog);
diff --git a/resources/js/components/tournament/Scoreboard.js b/resources/js/components/tournament/Scoreboard.js
deleted file mode 100644 (file)
index 27bb087..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Table } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from '../common/Icon';
-import Box from '../users/Box';
-import { comparePlacement } from '../../helpers/Participant';
-import { getRunners } from '../../helpers/Tournament';
-import { useUser } from '../../hooks/user';
-
-const getRowClassName = (tournament, participant, user) => {
-       const classNames = ['score'];
-       if (participant && user && participant.user_id == user.id) {
-               classNames.push('is-self');
-       }
-       return classNames.join(' ');
-};
-
-const getPlacementDisplay = participant => {
-       if (participant.placement === 1) {
-               return <Icon.FIRST_PLACE className="text-gold" size="lg" />;
-       }
-       if (participant.placement === 2) {
-               return <Icon.SECOND_PLACE className="text-silver" size="lg" />;
-       }
-       if (participant.placement === 3) {
-               return <Icon.THIRD_PLACE className="text-bronze" size="lg" />;
-       }
-       return participant.placement;
-};
-
-const twitchReg = /^https?:\/\/(www\.)?twitch\.tv/;
-const youtubeReg = /^https?:\/\/(www\.)?youtu(\.be|be\.)/;
-
-const getStreamVariant = participant => {
-       if (!participant || !participant.user || !participant.user.stream_link) {
-               return 'outline-secondary';
-       }
-       if (twitchReg.test(participant.user.stream_link)) {
-               return 'outline-twitch';
-       }
-       if (youtubeReg.test(participant.user.stream_link)) {
-               return 'outline-youtube';
-       }
-       return 'outline-secondary';
-};
-
-const getStreamIcon = participant => {
-       const variant = getStreamVariant(participant);
-       if (variant === 'outline-twitch') {
-               return <Icon.TWITCH title="" />;
-       }
-       if (variant === 'outline-youtube') {
-               return <Icon.YOUTUBE title="" />;
-       }
-       return <Icon.VIDEO title="" />;
-};
-
-const Scoreboard = ({ tournament }) => {
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       return <Table striped className="scoreboard align-middle">
-               <thead>
-                       <tr>
-                               <th className="text-center">{t('participants.placementShort')}</th>
-                               <th>{t('participants.participant')}</th>
-                               <th className="text-end">{t('participants.scoreShort')}</th>
-                       </tr>
-               </thead>
-               <tbody>
-               {getRunners(tournament).sort(comparePlacement).map(participant =>
-                       <tr className={getRowClassName(tournament, participant, user)} key={participant.id}>
-                               <td className="text-center">
-                                       {getPlacementDisplay(participant)}
-                               </td>
-                               <td>
-                                       <div className="d-flex align-items-center justify-content-between">
-                                               <Box user={participant.user} />
-                                               {participant.user.stream_link ?
-                                                       <Button
-                                                               href={participant.user.stream_link}
-                                                               size="sm"
-                                                               target="_blank"
-                                                               title={t('users.stream')}
-                                                               variant={getStreamVariant(participant)}
-                                                       >
-                                                               {getStreamIcon(participant)}
-                                                       </Button>
-                                               : null}
-                                       </div>
-                               </td>
-                               <td className="text-end">{participant.score}</td>
-                       </tr>
-               )}
-               </tbody>
-       </Table>;
-};
-
-Scoreboard.propTypes = {
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default Scoreboard;
diff --git a/resources/js/components/tournament/Scoreboard.jsx b/resources/js/components/tournament/Scoreboard.jsx
new file mode 100644 (file)
index 0000000..27bb087
--- /dev/null
@@ -0,0 +1,106 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Table } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../common/Icon';
+import Box from '../users/Box';
+import { comparePlacement } from '../../helpers/Participant';
+import { getRunners } from '../../helpers/Tournament';
+import { useUser } from '../../hooks/user';
+
+const getRowClassName = (tournament, participant, user) => {
+       const classNames = ['score'];
+       if (participant && user && participant.user_id == user.id) {
+               classNames.push('is-self');
+       }
+       return classNames.join(' ');
+};
+
+const getPlacementDisplay = participant => {
+       if (participant.placement === 1) {
+               return <Icon.FIRST_PLACE className="text-gold" size="lg" />;
+       }
+       if (participant.placement === 2) {
+               return <Icon.SECOND_PLACE className="text-silver" size="lg" />;
+       }
+       if (participant.placement === 3) {
+               return <Icon.THIRD_PLACE className="text-bronze" size="lg" />;
+       }
+       return participant.placement;
+};
+
+const twitchReg = /^https?:\/\/(www\.)?twitch\.tv/;
+const youtubeReg = /^https?:\/\/(www\.)?youtu(\.be|be\.)/;
+
+const getStreamVariant = participant => {
+       if (!participant || !participant.user || !participant.user.stream_link) {
+               return 'outline-secondary';
+       }
+       if (twitchReg.test(participant.user.stream_link)) {
+               return 'outline-twitch';
+       }
+       if (youtubeReg.test(participant.user.stream_link)) {
+               return 'outline-youtube';
+       }
+       return 'outline-secondary';
+};
+
+const getStreamIcon = participant => {
+       const variant = getStreamVariant(participant);
+       if (variant === 'outline-twitch') {
+               return <Icon.TWITCH title="" />;
+       }
+       if (variant === 'outline-youtube') {
+               return <Icon.YOUTUBE title="" />;
+       }
+       return <Icon.VIDEO title="" />;
+};
+
+const Scoreboard = ({ tournament }) => {
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       return <Table striped className="scoreboard align-middle">
+               <thead>
+                       <tr>
+                               <th className="text-center">{t('participants.placementShort')}</th>
+                               <th>{t('participants.participant')}</th>
+                               <th className="text-end">{t('participants.scoreShort')}</th>
+                       </tr>
+               </thead>
+               <tbody>
+               {getRunners(tournament).sort(comparePlacement).map(participant =>
+                       <tr className={getRowClassName(tournament, participant, user)} key={participant.id}>
+                               <td className="text-center">
+                                       {getPlacementDisplay(participant)}
+                               </td>
+                               <td>
+                                       <div className="d-flex align-items-center justify-content-between">
+                                               <Box user={participant.user} />
+                                               {participant.user.stream_link ?
+                                                       <Button
+                                                               href={participant.user.stream_link}
+                                                               size="sm"
+                                                               target="_blank"
+                                                               title={t('users.stream')}
+                                                               variant={getStreamVariant(participant)}
+                                                       >
+                                                               {getStreamIcon(participant)}
+                                                       </Button>
+                                               : null}
+                                       </div>
+                               </td>
+                               <td className="text-end">{participant.score}</td>
+                       </tr>
+               )}
+               </tbody>
+       </Table>;
+};
+
+Scoreboard.propTypes = {
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default Scoreboard;
diff --git a/resources/js/components/tournament/SettingsButton.js b/resources/js/components/tournament/SettingsButton.js
deleted file mode 100644 (file)
index 2ff1abd..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import SettingsDialog from './SettingsDialog';
-import Icon from '../common/Icon';
-import i18n from '../../i18n';
-
-const SettingsButton = ({ tournament }) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       return <>
-               <Button
-                       onClick={() => setShowDialog(true)}
-                       title={i18n.t('button.settings')}
-                       variant="outline-secondary"
-               >
-                       <Icon.SETTINGS title="" />
-               </Button>
-               <SettingsDialog
-                       onHide={() => setShowDialog(false)}
-                       tournament={tournament}
-                       show={showDialog}
-               />
-       </>;
-};
-
-SettingsButton.propTypes = {
-       tournament: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(SettingsButton);
diff --git a/resources/js/components/tournament/SettingsButton.jsx b/resources/js/components/tournament/SettingsButton.jsx
new file mode 100644 (file)
index 0000000..2ff1abd
--- /dev/null
@@ -0,0 +1,34 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import SettingsDialog from './SettingsDialog';
+import Icon from '../common/Icon';
+import i18n from '../../i18n';
+
+const SettingsButton = ({ tournament }) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       return <>
+               <Button
+                       onClick={() => setShowDialog(true)}
+                       title={i18n.t('button.settings')}
+                       variant="outline-secondary"
+               >
+                       <Icon.SETTINGS title="" />
+               </Button>
+               <SettingsDialog
+                       onHide={() => setShowDialog(false)}
+                       tournament={tournament}
+                       show={showDialog}
+               />
+       </>;
+};
+
+SettingsButton.propTypes = {
+       tournament: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(SettingsButton);
diff --git a/resources/js/components/tournament/SettingsDialog.js b/resources/js/components/tournament/SettingsDialog.js
deleted file mode 100644 (file)
index 46fbfd8..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Modal, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import DiscordForm from './DiscordForm';
-import DiscordSelect from '../common/DiscordSelect';
-import Icon from '../common/Icon';
-import ToggleSwitch from '../common/ToggleSwitch';
-import Tournament from '../../helpers/Tournament';
-import i18n from '../../i18n';
-
-const open = async tournament => {
-       try {
-               await axios.post(`/api/tournaments/${tournament.id}/open`);
-               toastr.success(i18n.t('tournaments.openSuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('tournaments.openError'));
-       }
-};
-
-const close = async tournament => {
-       try {
-               await axios.post(`/api/tournaments/${tournament.id}/close`);
-               toastr.success(i18n.t('tournaments.closeSuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('tournaments.closeError'));
-       }
-};
-
-const lock = async tournament => {
-       try {
-               await axios.post(`/api/tournaments/${tournament.id}/lock`);
-               toastr.success(i18n.t('tournaments.lockSuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('tournaments.lockError'));
-       }
-};
-
-const unlock = async tournament => {
-       try {
-               await axios.post(`/api/tournaments/${tournament.id}/unlock`);
-               toastr.success(i18n.t('tournaments.unlockSuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('tournaments.unlockError'));
-       }
-};
-
-const setDiscord = async (tournament, guild_id) => {
-       try {
-               await axios.post(`/api/tournaments/${tournament.id}/discord`, { guild_id });
-               toastr.success(i18n.t('tournaments.discordSuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('tournaments.discordError'));
-       }
-};
-
-const settings = async (tournament, params) => {
-       try {
-               await axios.post(`/api/tournaments/${tournament.id}/settings`, params);
-               toastr.success(i18n.t('tournaments.settingsSuccess'));
-       } catch (e) {
-               toastr.error(i18n.t('tournaments.settingsError'));
-       }
-};
-
-const inviteUrl = 'https://discordapp.com/oauth2/authorize?client_id=951113702839549982&scope=bot';
-
-const SettingsDialog = ({
-       onHide,
-       show,
-       tournament,
-}) =>
-<Modal
-       className="settings-dialog"
-       onHide={onHide}
-       show={show}
-       size={tournament.discord ? 'lg' : 'md'}
->
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('tournaments.settings')}
-               </Modal.Title>
-       </Modal.Header>
-       <Modal.Body>
-               <Row>
-                       <Col sm={tournament.discord ? 6 : 12}>
-                               {Tournament.hasSignup(tournament) ?
-                                       <div className="d-flex align-items-center justify-content-between mb-3">
-                                               <span>{i18n.t('tournaments.open')}</span>
-                                               <ToggleSwitch
-                                                       onChange={({ target: { value } }) => value
-                                                               ? open(tournament) : close(tournament)}
-                                                       value={tournament.accept_applications}
-                                               />
-                                       </div>
-                               : null}
-                               <div className="d-flex align-items-center justify-content-between mb-3">
-                                       <span>{i18n.t('tournaments.locked')}</span>
-                                       <ToggleSwitch
-                                               onChange={({ target: { value } }) => value
-                                                       ? lock(tournament) : unlock(tournament)}
-                                               value={tournament.locked}
-                                       />
-                               </div>
-                               <div className="d-flex align-items-center justify-content-between mb-3">
-                                       <span>{i18n.t('tournaments.showNumbers')}</span>
-                                       <ToggleSwitch
-                                               onChange={({ target: { value } }) =>
-                                                       settings(tournament, { show_numbers: value })}
-                                               value={tournament.show_numbers}
-                                       />
-                               </div>
-                               <div className="d-flex align-items-center justify-content-between">
-                                       <div>
-                                               <p>{i18n.t('tournaments.discord')}</p>
-                                               {!tournament.discord ?
-                                                       <div>
-                                                               <Button
-                                                                       href={inviteUrl}
-                                                                       target="_blank"
-                                                                       variant="discord"
-                                                               >
-                                                                       <Icon.DISCORD />
-                                                                       {' '}
-                                                                       {i18n.t('tournaments.inviteBot')}
-                                                               </Button>
-                                                       </div>
-                                               : null}
-                                       </div>
-                                       <DiscordSelect
-                                               onChange={({ target: { value } }) => setDiscord(tournament, value)}
-                                               value={tournament.discord}
-                                       />
-                               </div>
-                       </Col>
-                       {tournament.discord ?
-                               <Col sm={6}>
-                                       <DiscordForm tournament={tournament} />
-                               </Col>
-                       : null}
-               </Row>
-       </Modal.Body>
-       <Modal.Footer>
-               <Button onClick={onHide} variant="secondary">
-                       {i18n.t('button.close')}
-               </Button>
-       </Modal.Footer>
-</Modal>;
-
-SettingsDialog.propTypes = {
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-       tournament: PropTypes.shape({
-               accept_applications: PropTypes.bool,
-               discord: PropTypes.string,
-               locked: PropTypes.bool,
-               show_numbers: PropTypes.bool,
-       }),
-};
-
-export default withTranslation()(SettingsDialog);
diff --git a/resources/js/components/tournament/SettingsDialog.jsx b/resources/js/components/tournament/SettingsDialog.jsx
new file mode 100644 (file)
index 0000000..a40a0a1
--- /dev/null
@@ -0,0 +1,186 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import DiscordForm from './DiscordForm';
+import DiscordSelect from '../common/DiscordSelect';
+import Icon from '../common/Icon';
+import ToggleSwitch from '../common/ToggleSwitch';
+import Tournament from '../../helpers/Tournament';
+import i18n from '../../i18n';
+
+const open = async tournament => {
+       try {
+               await axios.post(`/api/tournaments/${tournament.id}/open`);
+               toastr.success(i18n.t('tournaments.openSuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('tournaments.openError'));
+       }
+};
+
+const close = async tournament => {
+       try {
+               await axios.post(`/api/tournaments/${tournament.id}/close`);
+               toastr.success(i18n.t('tournaments.closeSuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('tournaments.closeError'));
+       }
+};
+
+const lock = async tournament => {
+       try {
+               await axios.post(`/api/tournaments/${tournament.id}/lock`);
+               toastr.success(i18n.t('tournaments.lockSuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('tournaments.lockError'));
+       }
+};
+
+const unlock = async tournament => {
+       try {
+               await axios.post(`/api/tournaments/${tournament.id}/unlock`);
+               toastr.success(i18n.t('tournaments.unlockSuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('tournaments.unlockError'));
+       }
+};
+
+const setDiscord = async (tournament, guild_id) => {
+       try {
+               await axios.post(`/api/tournaments/${tournament.id}/discord`, { guild_id });
+               toastr.success(i18n.t('tournaments.discordSuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('tournaments.discordError'));
+       }
+};
+
+const settings = async (tournament, params) => {
+       try {
+               await axios.post(`/api/tournaments/${tournament.id}/settings`, params);
+               toastr.success(i18n.t('tournaments.settingsSuccess'));
+       } catch (e) {
+               toastr.error(i18n.t('tournaments.settingsError'));
+       }
+};
+
+const inviteUrl = 'https://discordapp.com/oauth2/authorize?client_id=951113702839549982&scope=bot';
+
+const SettingsDialog = ({
+       onHide,
+       show,
+       tournament,
+}) =>
+<Modal
+       className="settings-dialog"
+       onHide={onHide}
+       show={show}
+       size={tournament.discord ? 'lg' : 'md'}
+>
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t('tournaments.settings')}
+               </Modal.Title>
+       </Modal.Header>
+       <Modal.Body>
+               <Row>
+                       <Col sm={tournament.discord ? 6 : 12}>
+                               {Tournament.hasSignup(tournament) ?
+                                       <div className="d-flex align-items-center justify-content-between mb-3">
+                                               <span>{i18n.t('tournaments.open')}</span>
+                                               <ToggleSwitch
+                                                       onChange={({ target: { value } }) => value
+                                                               ? open(tournament) : close(tournament)}
+                                                       value={tournament.accept_applications}
+                                               />
+                                       </div>
+                               : null}
+                               <div className="d-flex align-items-center justify-content-between mb-3">
+                                       <span>{i18n.t('tournaments.locked')}</span>
+                                       <ToggleSwitch
+                                               onChange={({ target: { value } }) => value
+                                                       ? lock(tournament) : unlock(tournament)}
+                                               value={tournament.locked}
+                                       />
+                               </div>
+                               <div className="d-flex align-items-center justify-content-between mb-3">
+                                       <span>{i18n.t('tournaments.showNumbers')}</span>
+                                       <ToggleSwitch
+                                               onChange={({ target: { value } }) =>
+                                                       settings(tournament, { show_numbers: value })}
+                                               value={tournament.show_numbers}
+                                       />
+                               </div>
+                               <div className="d-flex align-items-center justify-content-between mb-3">
+                                       <span title={i18n.t('tournaments.resultRevealDescription')}>
+                                               {i18n.t('tournaments.resultReveal')}
+                                       </span>
+                                       <Form.Select
+                                               onChange={({ target: { value } }) =>
+                                                       settings(tournament, { result_reveal: value })}
+                                               style={{ width: '50%' }}
+                                               value={tournament.result_reveal}
+                                       >
+                                               {['never', 'finishers', 'participants', 'always'].map((key) =>
+                                                       <option
+                                                               key={key}
+                                                               title={i18n.t(`tournaments.resultRevealOptionDescription.${key}`)}
+                                                               value={key}
+                                                       >
+                                                               {i18n.t(`tournaments.resultRevealOption.${key}`)}
+                                                       </option>
+                                               )}
+                                       </Form.Select>
+                               </div>
+                               <div className="d-flex align-items-center justify-content-between">
+                                       <div>
+                                               <p>{i18n.t('tournaments.discord')}</p>
+                                               {!tournament.discord ?
+                                                       <div>
+                                                               <Button
+                                                                       href={inviteUrl}
+                                                                       target="_blank"
+                                                                       variant="discord"
+                                                               >
+                                                                       <Icon.DISCORD />
+                                                                       {' '}
+                                                                       {i18n.t('tournaments.inviteBot')}
+                                                               </Button>
+                                                       </div>
+                                               : null}
+                                       </div>
+                                       <DiscordSelect
+                                               onChange={({ target: { value } }) => setDiscord(tournament, value)}
+                                               value={tournament.discord}
+                                       />
+                               </div>
+                       </Col>
+                       {tournament.discord ?
+                               <Col sm={6}>
+                                       <DiscordForm tournament={tournament} />
+                               </Col>
+                       : null}
+               </Row>
+       </Modal.Body>
+       <Modal.Footer>
+               <Button onClick={onHide} variant="secondary">
+                       {i18n.t('button.close')}
+               </Button>
+       </Modal.Footer>
+</Modal>;
+
+SettingsDialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+       tournament: PropTypes.shape({
+               accept_applications: PropTypes.bool,
+               discord: PropTypes.string,
+               locked: PropTypes.bool,
+               result_reveal: PropTypes.string,
+               show_numbers: PropTypes.bool,
+       }),
+};
+
+export default withTranslation()(SettingsDialog);
diff --git a/resources/js/components/tracker/AutoTracking.js b/resources/js/components/tracker/AutoTracking.js
deleted file mode 100644 (file)
index dfa1972..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from '../common/Icon';
-import ToggleSwitch from '../common/ToggleSwitch';
-import {
-       IN_GAME_MODES,
-       RAM_ADDR,
-       SRAM_ADDR,
-       WRAM_ADDR,
-       buildPrizeMap,
-} from '../../helpers/alttp-ram';
-import { computeState } from '../../helpers/tracker';
-import { useSNES } from '../../hooks/snes';
-import { useTracker } from '../../hooks/tracker';
-
-const AutoTracking = () => {
-       const [enabled, setEnabled] = React.useState(false);
-       const [prizeMap, setPrizeMap] = React.useState(buildPrizeMap());
-
-       const {
-               disable: disableSNES,
-               enable: enableSNES,
-               openSettings,
-               sock,
-               status,
-       } = useSNES();
-       const { config, setAutoState } = useTracker();
-       const { t } = useTranslation();
-
-       const enable = React.useCallback(() => {
-               enableSNES();
-               setEnabled(true);
-       }, []);
-
-       const disable = React.useCallback(() => {
-               disableSNES();
-               setEnabled(false);
-       }, []);
-
-       React.useEffect(() => {
-               const savedSettings = localStorage.getItem('tracker.settings');
-               if (savedSettings) {
-                       const settings = JSON.parse(savedSettings);
-                       if (settings.autoTrack) {
-                               enable();
-                       }
-               }
-       }, []);
-
-       const saveSettings = React.useCallback((newSettings) => {
-               const savedSettings = localStorage.getItem('tracker.settings');
-               const settings = savedSettings
-                       ? { ...JSON.parse(savedSettings), ...newSettings }
-                       : newSettings;
-               localStorage.setItem('tracker.settings', JSON.stringify(settings));
-       }, []);
-
-       const toggle = React.useCallback(() => {
-               if (enabled) {
-                       disable();
-                       saveSettings({ autoTrack: false });
-               } else {
-                       enable();
-                       saveSettings({ autoTrack: true });
-               }
-       }, [enabled]);
-
-       // poll game and push state
-       React.useEffect(() => {
-               if (!enabled || status.error || !status.connected || !status.device) return;
-               const updateState = () => {
-                       const saveStart = WRAM_ADDR.SAVE_DATA;
-                       const saveSize = SRAM_ADDR.INV_END;
-                       sock.current.readWRAM(saveStart, saveSize, (data) => {
-                               const computed = computeState(config, data, prizeMap);
-                               setAutoState(computed);
-                       });
-               };
-               const fetchPrizes = () => {
-                       sock.current.readBytes(RAM_ADDR.PRIZE_MAP, 13, (prizes) => {
-                               sock.current.readBytes(RAM_ADDR.CRYSTAL_MAP, 13, (crystals) => {
-                                       setPrizeMap(m => {
-                                               const newMap = buildPrizeMap(prizes, crystals);
-                                               return JSON.stringify(m) === JSON.stringify(newMap) ? m : newMap;
-                                       });
-                               });
-                       });
-               };
-               const checkInGame = () => {
-                       sock.current.readWRAM(WRAM_ADDR.GAME_MODE, 1, (data) => {
-                               if (IN_GAME_MODES.includes(data[0])) {
-                                       fetchPrizes();
-                                       updateState();
-                               }
-                       });
-               };
-               const timer = setInterval(checkInGame, 1000);
-               return () => {
-                       clearInterval(timer);
-               };
-       }, [enabled && !status.error && status.connected && status.device, config, prizeMap, sock]);
-
-       const statusMsg = React.useMemo(() => {
-               if (!enabled) {
-                       return 'disabled';
-               }
-               if (status.error) {
-                       return 'error';
-               }
-               if (!status.connected) {
-                       return 'disconnected';
-               }
-               if (!status.device) {
-                       return 'no-device';
-               }
-               return 'tracking';
-       }, [enabled, status]);
-
-       return <div className="auto-tracking">
-               {['disconnected', 'error', 'no-device'].includes(statusMsg) ?
-                       <Icon.WARNING
-                               className="me-2 text-warning"
-                               size="lg"
-                               title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device  })}
-                       />
-               : null}
-               {['not-applicable', 'not-in-game'].includes(statusMsg) ?
-                       <Icon.INFO
-                               className="me-2 text-info"
-                               size="lg"
-                               title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device  })}
-                       />
-               : null}
-               <Button
-                       className="me-2"
-                       onClick={openSettings}
-                       size="sm"
-                       title={t('snes.settings')}
-                       variant="outline-secondary"
-               >
-                       <Icon.SETTINGS title="" />
-               </Button>
-               <ToggleSwitch
-                       onChange={toggle}
-                       title={t('autoTracking.heading')}
-                       value={enabled}
-               />
-       </div>;
-};
-
-export default AutoTracking;
diff --git a/resources/js/components/tracker/AutoTracking.jsx b/resources/js/components/tracker/AutoTracking.jsx
new file mode 100644 (file)
index 0000000..dfa1972
--- /dev/null
@@ -0,0 +1,153 @@
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../common/Icon';
+import ToggleSwitch from '../common/ToggleSwitch';
+import {
+       IN_GAME_MODES,
+       RAM_ADDR,
+       SRAM_ADDR,
+       WRAM_ADDR,
+       buildPrizeMap,
+} from '../../helpers/alttp-ram';
+import { computeState } from '../../helpers/tracker';
+import { useSNES } from '../../hooks/snes';
+import { useTracker } from '../../hooks/tracker';
+
+const AutoTracking = () => {
+       const [enabled, setEnabled] = React.useState(false);
+       const [prizeMap, setPrizeMap] = React.useState(buildPrizeMap());
+
+       const {
+               disable: disableSNES,
+               enable: enableSNES,
+               openSettings,
+               sock,
+               status,
+       } = useSNES();
+       const { config, setAutoState } = useTracker();
+       const { t } = useTranslation();
+
+       const enable = React.useCallback(() => {
+               enableSNES();
+               setEnabled(true);
+       }, []);
+
+       const disable = React.useCallback(() => {
+               disableSNES();
+               setEnabled(false);
+       }, []);
+
+       React.useEffect(() => {
+               const savedSettings = localStorage.getItem('tracker.settings');
+               if (savedSettings) {
+                       const settings = JSON.parse(savedSettings);
+                       if (settings.autoTrack) {
+                               enable();
+                       }
+               }
+       }, []);
+
+       const saveSettings = React.useCallback((newSettings) => {
+               const savedSettings = localStorage.getItem('tracker.settings');
+               const settings = savedSettings
+                       ? { ...JSON.parse(savedSettings), ...newSettings }
+                       : newSettings;
+               localStorage.setItem('tracker.settings', JSON.stringify(settings));
+       }, []);
+
+       const toggle = React.useCallback(() => {
+               if (enabled) {
+                       disable();
+                       saveSettings({ autoTrack: false });
+               } else {
+                       enable();
+                       saveSettings({ autoTrack: true });
+               }
+       }, [enabled]);
+
+       // poll game and push state
+       React.useEffect(() => {
+               if (!enabled || status.error || !status.connected || !status.device) return;
+               const updateState = () => {
+                       const saveStart = WRAM_ADDR.SAVE_DATA;
+                       const saveSize = SRAM_ADDR.INV_END;
+                       sock.current.readWRAM(saveStart, saveSize, (data) => {
+                               const computed = computeState(config, data, prizeMap);
+                               setAutoState(computed);
+                       });
+               };
+               const fetchPrizes = () => {
+                       sock.current.readBytes(RAM_ADDR.PRIZE_MAP, 13, (prizes) => {
+                               sock.current.readBytes(RAM_ADDR.CRYSTAL_MAP, 13, (crystals) => {
+                                       setPrizeMap(m => {
+                                               const newMap = buildPrizeMap(prizes, crystals);
+                                               return JSON.stringify(m) === JSON.stringify(newMap) ? m : newMap;
+                                       });
+                               });
+                       });
+               };
+               const checkInGame = () => {
+                       sock.current.readWRAM(WRAM_ADDR.GAME_MODE, 1, (data) => {
+                               if (IN_GAME_MODES.includes(data[0])) {
+                                       fetchPrizes();
+                                       updateState();
+                               }
+                       });
+               };
+               const timer = setInterval(checkInGame, 1000);
+               return () => {
+                       clearInterval(timer);
+               };
+       }, [enabled && !status.error && status.connected && status.device, config, prizeMap, sock]);
+
+       const statusMsg = React.useMemo(() => {
+               if (!enabled) {
+                       return 'disabled';
+               }
+               if (status.error) {
+                       return 'error';
+               }
+               if (!status.connected) {
+                       return 'disconnected';
+               }
+               if (!status.device) {
+                       return 'no-device';
+               }
+               return 'tracking';
+       }, [enabled, status]);
+
+       return <div className="auto-tracking">
+               {['disconnected', 'error', 'no-device'].includes(statusMsg) ?
+                       <Icon.WARNING
+                               className="me-2 text-warning"
+                               size="lg"
+                               title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device  })}
+                       />
+               : null}
+               {['not-applicable', 'not-in-game'].includes(statusMsg) ?
+                       <Icon.INFO
+                               className="me-2 text-info"
+                               size="lg"
+                               title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device  })}
+                       />
+               : null}
+               <Button
+                       className="me-2"
+                       onClick={openSettings}
+                       size="sm"
+                       title={t('snes.settings')}
+                       variant="outline-secondary"
+               >
+                       <Icon.SETTINGS title="" />
+               </Button>
+               <ToggleSwitch
+                       onChange={toggle}
+                       title={t('autoTracking.heading')}
+                       value={enabled}
+               />
+       </div>;
+};
+
+export default AutoTracking;
diff --git a/resources/js/components/tracker/Canvas.js b/resources/js/components/tracker/Canvas.js
deleted file mode 100644 (file)
index 62dafe1..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-import { drag } from 'd3-drag';
-import { select } from 'd3-selection';
-import React from 'react';
-
-import Dungeons from './Dungeons';
-import Items from './Items';
-import Map from './Map';
-import ToggleIcon from './ToggleIcon';
-import ZeldaIcon from '../common/ZeldaIcon';
-import { shouldShowDungeonItem } from '../../helpers/tracker';
-import { useTracker } from '../../hooks/tracker';
-
-const LAYOUTS = {
-       defaultHorizontal: {
-               width: 100,
-               height: 60,
-               itemsTransform: 'translate(1 1) scale(22)',
-               dungeonColumns: 4,
-               dungeonsTransform: 'translate(1 39) scale(98)',
-               mapTransform: 'translate(24 0) scale(76)',
-       },
-       defaultVertical: {
-               width: 100,
-               height: 100,
-               itemsTransform: 'translate(10 1) scale(30)',
-               dungeonColumns: 2,
-               dungeonsTransform: 'translate(1 51) scale(48)',
-               mapTransform: 'translate(50 0) scale(50)',
-       },
-       manyDungeonItemsVertical: {
-               width: 80,
-               height: 100,
-               itemsTransform: 'translate(1 1) scale(27)',
-               dungeonColumns: 1,
-               dungeonsTransform: 'translate(1 48) scale(24)',
-               mapTransform: 'translate(30 0) scale(50)',
-       },
-};
-
-const Canvas = () => {
-       const [dragging, setDragging] = React.useState(null);
-       const { addPin, config, pins, removePin } = useTracker();
-
-       const layout = React.useMemo(() => {
-               if (config.mapLayout === 'vertical') {
-                       let count = 0;
-                       if (shouldShowDungeonItem(config, 'Map')) {
-                               ++count;
-                       }
-                       if (shouldShowDungeonItem(config, 'Compass')) {
-                               ++count;
-                       }
-                       if (shouldShowDungeonItem(config, 'Small')) {
-                               ++count;
-                       }
-                       if (shouldShowDungeonItem(config, 'Big')) {
-                               ++count;
-                       }
-                       const compact = config.compactKeysanity && count === 4;
-                       return !compact && count > 2
-                               ? LAYOUTS.manyDungeonItemsVertical : LAYOUTS.defaultVertical;
-               } else {
-                       return LAYOUTS.defaultHorizontal;
-               }
-       }, [config]);
-
-       React.useEffect(() => {
-               const canvas = select('.canvas');
-               const bbox = canvas.select('.background');
-               const start = { x: 0, y: 0 };
-               const onStart = function (e) {
-                       start.x = e.x;
-                       start.y = e.y;
-               };
-               const onDrag = function (e) {
-                       const bounds = bbox.node().getBoundingClientRect();
-                       const distance = Math.max(Math.abs(e.x - start.x), Math.abs(e.y - start.y));
-                       if (distance > 5) {
-                               setDragging({
-                                       icon: this.dataset['icon'],
-                                       x: (e.x - bounds.x) / bounds.width,
-                                       y: (e.y - bounds.y) / bounds.height,
-                               });
-                       } else {
-                               setDragging(null);
-                       }
-               };
-               const onEnd = function (e) {
-                       const bounds = bbox.node().getBoundingClientRect();
-                       setDragging(null);
-                       const distance = Math.max(Math.abs(e.x - start.x), Math.abs(e.y - start.y));
-                       if (distance > 5) {
-                               addPin({
-                                       icon: this.dataset['icon'],
-                                       x: (e.x - bounds.x) / bounds.width,
-                                       y: (e.y - bounds.y) / bounds.height,
-                               });
-                               if (this.classList.contains('map-pin')) {
-                                       let id = 0;
-                                       this.classList.forEach(name => {
-                                               if (name.startsWith('map-pin-')) {
-                                                       id = parseInt(name.substr(8), 10);
-                                               }
-                                       });
-                                       removePin({ id });
-                               }
-                       }
-               };
-               const selection = canvas.selectAll('.toggle-icon');
-               const draggable = drag()
-                       .container(bbox)
-                       .clickDistance(5)
-                       .on('start', onStart)
-                       .on('drag', onDrag)
-                       .on('end', onEnd);
-               selection.call(draggable);
-               return () => {
-                       selection.on('.drag', null);
-               };
-       }, [pins, removePin]);
-
-       return <svg
-               xmlns="http://www.w3.org/2000/svg"
-               className="canvas"
-               width={layout.width}
-               height={layout.height}
-               viewBox={`0 0 ${layout.width} ${layout.height}`}
-               onContextMenu={(e) => {
-                       e.preventDefault();
-                       e.stopPropagation();
-               }}
-       >
-               <rect
-                       className="background"
-                       fill="transparent"
-                       x="0" y="0"
-                       width={layout.width}
-                       height={layout.height}
-               />
-               <g className="items" transform={layout.itemsTransform}>
-                       <Items />
-               </g>
-               <g className="dungeons" transform={layout.dungeonsTransform}>
-                       <Dungeons columns={layout.dungeonColumns} />
-               </g>
-               <g className="tracker-map" transform={layout.mapTransform}>
-                       <Map />
-               </g>
-               <g className="pins">
-                       {pins.map(pin =>
-                               <ToggleIcon
-                                       key={pin.id}
-                                       className={`map-pin map-pin-${pin.id}`}
-                                       controller={ToggleIcon.pinController(pin, removePin)}
-                                       icons={[pin.icon]}
-                                       svg
-                                       transform={
-                                               `translate(${pin.x * layout.width} ${pin.y * layout.height}) scale(3)`
-                                       }
-                               />
-                       )}
-               </g>
-               {dragging ?
-                       <g transform={
-                               `translate(${dragging.x * layout.width} ${dragging.y * layout.height}) scale(4)`
-                       }>
-                               <ZeldaIcon name={dragging.icon} svg />
-                       </g>
-               : null}
-       </svg>;
-};
-
-export default Canvas;
diff --git a/resources/js/components/tracker/Canvas.jsx b/resources/js/components/tracker/Canvas.jsx
new file mode 100644 (file)
index 0000000..62dafe1
--- /dev/null
@@ -0,0 +1,173 @@
+import { drag } from 'd3-drag';
+import { select } from 'd3-selection';
+import React from 'react';
+
+import Dungeons from './Dungeons';
+import Items from './Items';
+import Map from './Map';
+import ToggleIcon from './ToggleIcon';
+import ZeldaIcon from '../common/ZeldaIcon';
+import { shouldShowDungeonItem } from '../../helpers/tracker';
+import { useTracker } from '../../hooks/tracker';
+
+const LAYOUTS = {
+       defaultHorizontal: {
+               width: 100,
+               height: 60,
+               itemsTransform: 'translate(1 1) scale(22)',
+               dungeonColumns: 4,
+               dungeonsTransform: 'translate(1 39) scale(98)',
+               mapTransform: 'translate(24 0) scale(76)',
+       },
+       defaultVertical: {
+               width: 100,
+               height: 100,
+               itemsTransform: 'translate(10 1) scale(30)',
+               dungeonColumns: 2,
+               dungeonsTransform: 'translate(1 51) scale(48)',
+               mapTransform: 'translate(50 0) scale(50)',
+       },
+       manyDungeonItemsVertical: {
+               width: 80,
+               height: 100,
+               itemsTransform: 'translate(1 1) scale(27)',
+               dungeonColumns: 1,
+               dungeonsTransform: 'translate(1 48) scale(24)',
+               mapTransform: 'translate(30 0) scale(50)',
+       },
+};
+
+const Canvas = () => {
+       const [dragging, setDragging] = React.useState(null);
+       const { addPin, config, pins, removePin } = useTracker();
+
+       const layout = React.useMemo(() => {
+               if (config.mapLayout === 'vertical') {
+                       let count = 0;
+                       if (shouldShowDungeonItem(config, 'Map')) {
+                               ++count;
+                       }
+                       if (shouldShowDungeonItem(config, 'Compass')) {
+                               ++count;
+                       }
+                       if (shouldShowDungeonItem(config, 'Small')) {
+                               ++count;
+                       }
+                       if (shouldShowDungeonItem(config, 'Big')) {
+                               ++count;
+                       }
+                       const compact = config.compactKeysanity && count === 4;
+                       return !compact && count > 2
+                               ? LAYOUTS.manyDungeonItemsVertical : LAYOUTS.defaultVertical;
+               } else {
+                       return LAYOUTS.defaultHorizontal;
+               }
+       }, [config]);
+
+       React.useEffect(() => {
+               const canvas = select('.canvas');
+               const bbox = canvas.select('.background');
+               const start = { x: 0, y: 0 };
+               const onStart = function (e) {
+                       start.x = e.x;
+                       start.y = e.y;
+               };
+               const onDrag = function (e) {
+                       const bounds = bbox.node().getBoundingClientRect();
+                       const distance = Math.max(Math.abs(e.x - start.x), Math.abs(e.y - start.y));
+                       if (distance > 5) {
+                               setDragging({
+                                       icon: this.dataset['icon'],
+                                       x: (e.x - bounds.x) / bounds.width,
+                                       y: (e.y - bounds.y) / bounds.height,
+                               });
+                       } else {
+                               setDragging(null);
+                       }
+               };
+               const onEnd = function (e) {
+                       const bounds = bbox.node().getBoundingClientRect();
+                       setDragging(null);
+                       const distance = Math.max(Math.abs(e.x - start.x), Math.abs(e.y - start.y));
+                       if (distance > 5) {
+                               addPin({
+                                       icon: this.dataset['icon'],
+                                       x: (e.x - bounds.x) / bounds.width,
+                                       y: (e.y - bounds.y) / bounds.height,
+                               });
+                               if (this.classList.contains('map-pin')) {
+                                       let id = 0;
+                                       this.classList.forEach(name => {
+                                               if (name.startsWith('map-pin-')) {
+                                                       id = parseInt(name.substr(8), 10);
+                                               }
+                                       });
+                                       removePin({ id });
+                               }
+                       }
+               };
+               const selection = canvas.selectAll('.toggle-icon');
+               const draggable = drag()
+                       .container(bbox)
+                       .clickDistance(5)
+                       .on('start', onStart)
+                       .on('drag', onDrag)
+                       .on('end', onEnd);
+               selection.call(draggable);
+               return () => {
+                       selection.on('.drag', null);
+               };
+       }, [pins, removePin]);
+
+       return <svg
+               xmlns="http://www.w3.org/2000/svg"
+               className="canvas"
+               width={layout.width}
+               height={layout.height}
+               viewBox={`0 0 ${layout.width} ${layout.height}`}
+               onContextMenu={(e) => {
+                       e.preventDefault();
+                       e.stopPropagation();
+               }}
+       >
+               <rect
+                       className="background"
+                       fill="transparent"
+                       x="0" y="0"
+                       width={layout.width}
+                       height={layout.height}
+               />
+               <g className="items" transform={layout.itemsTransform}>
+                       <Items />
+               </g>
+               <g className="dungeons" transform={layout.dungeonsTransform}>
+                       <Dungeons columns={layout.dungeonColumns} />
+               </g>
+               <g className="tracker-map" transform={layout.mapTransform}>
+                       <Map />
+               </g>
+               <g className="pins">
+                       {pins.map(pin =>
+                               <ToggleIcon
+                                       key={pin.id}
+                                       className={`map-pin map-pin-${pin.id}`}
+                                       controller={ToggleIcon.pinController(pin, removePin)}
+                                       icons={[pin.icon]}
+                                       svg
+                                       transform={
+                                               `translate(${pin.x * layout.width} ${pin.y * layout.height}) scale(3)`
+                                       }
+                               />
+                       )}
+               </g>
+               {dragging ?
+                       <g transform={
+                               `translate(${dragging.x * layout.width} ${dragging.y * layout.height}) scale(4)`
+                       }>
+                               <ZeldaIcon name={dragging.icon} svg />
+                       </g>
+               : null}
+       </svg>;
+};
+
+export default Canvas;
diff --git a/resources/js/components/tracker/ConfigDialog.js b/resources/js/components/tracker/ConfigDialog.js
deleted file mode 100644 (file)
index 9d6b5be..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Col, Form, Modal, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import LargeCheck from '../common/LargeCheck';
-import { getConfigValue } from '../../helpers/tracker';
-import { useTracker } from '../../hooks/tracker';
-
-const ConfigDialog = ({
-       onHide,
-       show,
-}) => {
-       const { config, saveConfig } = useTracker();
-       const { t } = useTranslation();
-
-       const handleChange = React.useCallback(({ target: { name, value } }) => {
-               saveConfig({ [name]: value });
-       }, [saveConfig]);
-
-       return <Modal className="tracker-config-dialog" onHide={onHide} show={show} size="lg">
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {t('tracker.config.title')}
-                       </Modal.Title>
-               </Modal.Header>
-               <Modal.Body>
-                       <Row>
-                               <Col sm={6}>
-                                       <h3>{t('tracker.config.logic')}</h3>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.worldState"
-                                       >
-                                               <Form.Label>{t('tracker.config.worldState')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="worldState"
-                                                       onChange={handleChange}
-                                                       value={getConfigValue(config, 'worldState', 'open')}
-                                               >
-                                                       {['open', 'inverted'].map(n =>
-                                                               <option key={n} value={n}>
-                                                                       {t(`tracker.config.worldStates.${n}`)}
-                                                               </option>
-                                                       )}
-                                               </Form.Select>
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.glitches"
-                                       >
-                                               <Form.Label>{t('tracker.config.glitches')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="glitches"
-                                                       onChange={handleChange}
-                                                       value={getConfigValue(config, 'glitches', 'none')}
-                                               >
-                                                       {['none', 'owg', 'hmg', 'mg', 'nl'].map(n =>
-                                                               <option key={n} value={n}>
-                                                                       {t(`tracker.config.glitchRules.${n}`)}
-                                                               </option>
-                                                       )}
-                                               </Form.Select>
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.bossShuffle"
-                                       >
-                                               <Form.Label>{t('tracker.config.bossShuffle')}</Form.Label>
-                                               <Form.Control
-                                                       as={LargeCheck}
-                                                       name="bossShuffle"
-                                                       onChange={handleChange}
-                                                       value={!!config.bossShuffle}
-                                               />
-                                       </Form.Group>
-                               </Col>
-                               <Col sm={6}>
-                                       <h3>{t('tracker.config.goal')}</h3>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.gtCrystals"
-                                       >
-                                               <Form.Label>{t('tracker.config.gtCrystals')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="gt-crystals"
-                                                       onChange={handleChange}
-                                                       value={getConfigValue(config, 'gt-crystals', 7)}
-                                               >
-                                                       {['?', 0, 1, 2, 3, 4, 5, 6, 7].map(n =>
-                                                               <option key={n} value={n}>
-                                                                       {n}
-                                                               </option>
-                                                       )}
-                                               </Form.Select>
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.ganonCrystals"
-                                       >
-                                               <Form.Label>{t('tracker.config.ganonCrystals')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="ganon-crystals"
-                                                       onChange={handleChange}
-                                                       value={getConfigValue(config, 'ganon-crystals', 7)}
-                                               >
-                                                       {['?', 0, 1, 2, 3, 4, 5, 6, 7].map(n =>
-                                                               <option key={n} value={n}>
-                                                                       {n}
-                                                               </option>
-                                                       )}
-                                               </Form.Select>
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.goal"
-                                       >
-                                               <Form.Label>{t('tracker.config.goal')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="goal"
-                                                       onChange={handleChange}
-                                                       value={getConfigValue(config, 'goal', 'ganon')}
-                                               >
-                                                       {['ganon', 'fast', 'ad', 'ped', 'trinity', 'thunt', 'ghunt'].map(n =>
-                                                               <option key={n} value={n}>
-                                                                       {t(`tracker.config.goals.${n}`)}
-                                                               </option>
-                                                       )}
-                                               </Form.Select>
-                                       </Form.Group>
-                               </Col>
-                       </Row>
-                       <Row className="mt-3">
-                               <Col sm={6}>
-                                       <h3>{t('tracker.config.wildItems')}</h3>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.wildMap"
-                                       >
-                                               <Form.Label>{t('tracker.config.wildMap')}</Form.Label>
-                                               <Form.Control
-                                                       as={LargeCheck}
-                                                       name="wildMap"
-                                                       onChange={handleChange}
-                                                       value={!!config.wildMap}
-                                               />
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.wildCompass"
-                                       >
-                                               <Form.Label>{t('tracker.config.wildCompass')}</Form.Label>
-                                               <Form.Control
-                                                       as={LargeCheck}
-                                                       name="wildCompass"
-                                                       onChange={handleChange}
-                                                       value={!!config.wildCompass}
-                                               />
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.wildSmall"
-                                       >
-                                               <Form.Label>{t('tracker.config.wildSmall')}</Form.Label>
-                                               <Form.Control
-                                                       as={LargeCheck}
-                                                       name="wildSmall"
-                                                       onChange={handleChange}
-                                                       value={!!config.wildSmall}
-                                               />
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.wildBig"
-                                       >
-                                               <Form.Label>{t('tracker.config.wildBig')}</Form.Label>
-                                               <Form.Control
-                                                       as={LargeCheck}
-                                                       name="wildBig"
-                                                       onChange={handleChange}
-                                                       value={!!config.wildBig}
-                                               />
-                                       </Form.Group>
-                               </Col>
-                               <Col sm={6}>
-                                       <h3>{t('tracker.config.showItems')}</h3>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.showMap"
-                                       >
-                                               <Form.Label>{t('tracker.config.showMap')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="showMap"
-                                                       onChange={handleChange}
-                                                       value={config.showMap || 'always'}
-                                               >
-                                                       <option value="never">
-                                                               {t('tracker.config.showItemOptions.never')}
-                                                       </option>
-                                                       <option value="situational">
-                                                               {t('tracker.config.showItemOptions.situational')}
-                                                       </option>
-                                                       <option value="always">
-                                                               {t('tracker.config.showItemOptions.always')}
-                                                       </option>
-                                               </Form.Select>
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.showCompass"
-                                       >
-                                               <Form.Label>{t('tracker.config.showCompass')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="showCompass"
-                                                       onChange={handleChange}
-                                                       value={config.showCompass || 'always'}
-                                               >
-                                                       <option value="never">
-                                                               {t('tracker.config.showItemOptions.never')}
-                                                       </option>
-                                                       <option value="situational">
-                                                               {t('tracker.config.showItemOptions.situational')}
-                                                       </option>
-                                                       <option value="always">
-                                                               {t('tracker.config.showItemOptions.always')}
-                                                       </option>
-                                               </Form.Select>
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.showSmall"
-                                       >
-                                               <Form.Label>{t('tracker.config.showSmall')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="showSmall"
-                                                       onChange={handleChange}
-                                                       value={config.showSmall || 'always'}
-                                               >
-                                                       <option value="never">
-                                                               {t('tracker.config.showItemOptions.never')}
-                                                       </option>
-                                                       <option value="situational">
-                                                               {t('tracker.config.showItemOptions.situational')}
-                                                       </option>
-                                                       <option value="always">
-                                                               {t('tracker.config.showItemOptions.always')}
-                                                       </option>
-                                               </Form.Select>
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.showBig"
-                                       >
-                                               <Form.Label>{t('tracker.config.showBig')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="showBig"
-                                                       onChange={handleChange}
-                                                       value={config.showBig || 'always'}
-                                               >
-                                                       <option value="never">
-                                                               {t('tracker.config.showItemOptions.never')}
-                                                       </option>
-                                                       <option value="situational">
-                                                               {t('tracker.config.showItemOptions.situational')}
-                                                       </option>
-                                                       <option value="always">
-                                                               {t('tracker.config.showItemOptions.always')}
-                                                       </option>
-                                               </Form.Select>
-                                       </Form.Group>
-                               </Col>
-                       </Row>
-                       <Row>
-                               <Col sm={6}>
-                                       <h3>{t('tracker.config.layout')}</h3>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.mapLayout"
-                                       >
-                                               <Form.Label>{t('tracker.config.mapLayout')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="mapLayout"
-                                                       onChange={handleChange}
-                                                       value={getConfigValue(config, 'mapLayout', 'horizontal')}
-                                               >
-                                                       {['horizontal', 'vertical'].map(n =>
-                                                               <option key={n} value={n}>
-                                                                       {t(`tracker.config.mapLayouts.${n}`)}
-                                                               </option>
-                                                       )}
-                                               </Form.Select>
-                                       </Form.Group>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.compactKeysanity"
-                                       >
-                                               <Form.Label>{t('tracker.config.compactKeysanity')}</Form.Label>
-                                               <Form.Control
-                                                       as={LargeCheck}
-                                                       name="compactKeysanity"
-                                                       onChange={handleChange}
-                                                       value={!!config.compactKeysanity}
-                                               />
-                                       </Form.Group>
-                               </Col>
-                               <Col sm={6}>
-                                       <h3>{t('tracker.config.calculation')}</h3>
-                                       <Form.Group
-                                               className="d-flex justify-content-between my-2"
-                                               controlId="tracker.checkCalculation"
-                                       >
-                                               <Form.Label>{t('tracker.config.checkCalculation')}</Form.Label>
-                                               <Form.Select
-                                                       className="w-auto"
-                                                       name="checkCalculation"
-                                                       onChange={handleChange}
-                                                       value={getConfigValue(config, 'checkCalculation', 'room-data')}
-                                               >
-                                                       {['inventory', 'room-data'].map(n =>
-                                                               <option key={n} value={n}>
-                                                                       {t(`tracker.config.checkCalculations.${n}`)}
-                                                               </option>
-                                                       )}
-                                               </Form.Select>
-                                       </Form.Group>
-                               </Col>
-                       </Row>
-               </Modal.Body>
-       </Modal>;
-};
-
-ConfigDialog.propTypes = {
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-};
-
-export default ConfigDialog;
diff --git a/resources/js/components/tracker/ConfigDialog.jsx b/resources/js/components/tracker/ConfigDialog.jsx
new file mode 100644 (file)
index 0000000..9d6b5be
--- /dev/null
@@ -0,0 +1,347 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Col, Form, Modal, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import LargeCheck from '../common/LargeCheck';
+import { getConfigValue } from '../../helpers/tracker';
+import { useTracker } from '../../hooks/tracker';
+
+const ConfigDialog = ({
+       onHide,
+       show,
+}) => {
+       const { config, saveConfig } = useTracker();
+       const { t } = useTranslation();
+
+       const handleChange = React.useCallback(({ target: { name, value } }) => {
+               saveConfig({ [name]: value });
+       }, [saveConfig]);
+
+       return <Modal className="tracker-config-dialog" onHide={onHide} show={show} size="lg">
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t('tracker.config.title')}
+                       </Modal.Title>
+               </Modal.Header>
+               <Modal.Body>
+                       <Row>
+                               <Col sm={6}>
+                                       <h3>{t('tracker.config.logic')}</h3>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.worldState"
+                                       >
+                                               <Form.Label>{t('tracker.config.worldState')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="worldState"
+                                                       onChange={handleChange}
+                                                       value={getConfigValue(config, 'worldState', 'open')}
+                                               >
+                                                       {['open', 'inverted'].map(n =>
+                                                               <option key={n} value={n}>
+                                                                       {t(`tracker.config.worldStates.${n}`)}
+                                                               </option>
+                                                       )}
+                                               </Form.Select>
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.glitches"
+                                       >
+                                               <Form.Label>{t('tracker.config.glitches')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="glitches"
+                                                       onChange={handleChange}
+                                                       value={getConfigValue(config, 'glitches', 'none')}
+                                               >
+                                                       {['none', 'owg', 'hmg', 'mg', 'nl'].map(n =>
+                                                               <option key={n} value={n}>
+                                                                       {t(`tracker.config.glitchRules.${n}`)}
+                                                               </option>
+                                                       )}
+                                               </Form.Select>
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.bossShuffle"
+                                       >
+                                               <Form.Label>{t('tracker.config.bossShuffle')}</Form.Label>
+                                               <Form.Control
+                                                       as={LargeCheck}
+                                                       name="bossShuffle"
+                                                       onChange={handleChange}
+                                                       value={!!config.bossShuffle}
+                                               />
+                                       </Form.Group>
+                               </Col>
+                               <Col sm={6}>
+                                       <h3>{t('tracker.config.goal')}</h3>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.gtCrystals"
+                                       >
+                                               <Form.Label>{t('tracker.config.gtCrystals')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="gt-crystals"
+                                                       onChange={handleChange}
+                                                       value={getConfigValue(config, 'gt-crystals', 7)}
+                                               >
+                                                       {['?', 0, 1, 2, 3, 4, 5, 6, 7].map(n =>
+                                                               <option key={n} value={n}>
+                                                                       {n}
+                                                               </option>
+                                                       )}
+                                               </Form.Select>
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.ganonCrystals"
+                                       >
+                                               <Form.Label>{t('tracker.config.ganonCrystals')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="ganon-crystals"
+                                                       onChange={handleChange}
+                                                       value={getConfigValue(config, 'ganon-crystals', 7)}
+                                               >
+                                                       {['?', 0, 1, 2, 3, 4, 5, 6, 7].map(n =>
+                                                               <option key={n} value={n}>
+                                                                       {n}
+                                                               </option>
+                                                       )}
+                                               </Form.Select>
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.goal"
+                                       >
+                                               <Form.Label>{t('tracker.config.goal')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="goal"
+                                                       onChange={handleChange}
+                                                       value={getConfigValue(config, 'goal', 'ganon')}
+                                               >
+                                                       {['ganon', 'fast', 'ad', 'ped', 'trinity', 'thunt', 'ghunt'].map(n =>
+                                                               <option key={n} value={n}>
+                                                                       {t(`tracker.config.goals.${n}`)}
+                                                               </option>
+                                                       )}
+                                               </Form.Select>
+                                       </Form.Group>
+                               </Col>
+                       </Row>
+                       <Row className="mt-3">
+                               <Col sm={6}>
+                                       <h3>{t('tracker.config.wildItems')}</h3>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.wildMap"
+                                       >
+                                               <Form.Label>{t('tracker.config.wildMap')}</Form.Label>
+                                               <Form.Control
+                                                       as={LargeCheck}
+                                                       name="wildMap"
+                                                       onChange={handleChange}
+                                                       value={!!config.wildMap}
+                                               />
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.wildCompass"
+                                       >
+                                               <Form.Label>{t('tracker.config.wildCompass')}</Form.Label>
+                                               <Form.Control
+                                                       as={LargeCheck}
+                                                       name="wildCompass"
+                                                       onChange={handleChange}
+                                                       value={!!config.wildCompass}
+                                               />
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.wildSmall"
+                                       >
+                                               <Form.Label>{t('tracker.config.wildSmall')}</Form.Label>
+                                               <Form.Control
+                                                       as={LargeCheck}
+                                                       name="wildSmall"
+                                                       onChange={handleChange}
+                                                       value={!!config.wildSmall}
+                                               />
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.wildBig"
+                                       >
+                                               <Form.Label>{t('tracker.config.wildBig')}</Form.Label>
+                                               <Form.Control
+                                                       as={LargeCheck}
+                                                       name="wildBig"
+                                                       onChange={handleChange}
+                                                       value={!!config.wildBig}
+                                               />
+                                       </Form.Group>
+                               </Col>
+                               <Col sm={6}>
+                                       <h3>{t('tracker.config.showItems')}</h3>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.showMap"
+                                       >
+                                               <Form.Label>{t('tracker.config.showMap')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="showMap"
+                                                       onChange={handleChange}
+                                                       value={config.showMap || 'always'}
+                                               >
+                                                       <option value="never">
+                                                               {t('tracker.config.showItemOptions.never')}
+                                                       </option>
+                                                       <option value="situational">
+                                                               {t('tracker.config.showItemOptions.situational')}
+                                                       </option>
+                                                       <option value="always">
+                                                               {t('tracker.config.showItemOptions.always')}
+                                                       </option>
+                                               </Form.Select>
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.showCompass"
+                                       >
+                                               <Form.Label>{t('tracker.config.showCompass')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="showCompass"
+                                                       onChange={handleChange}
+                                                       value={config.showCompass || 'always'}
+                                               >
+                                                       <option value="never">
+                                                               {t('tracker.config.showItemOptions.never')}
+                                                       </option>
+                                                       <option value="situational">
+                                                               {t('tracker.config.showItemOptions.situational')}
+                                                       </option>
+                                                       <option value="always">
+                                                               {t('tracker.config.showItemOptions.always')}
+                                                       </option>
+                                               </Form.Select>
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.showSmall"
+                                       >
+                                               <Form.Label>{t('tracker.config.showSmall')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="showSmall"
+                                                       onChange={handleChange}
+                                                       value={config.showSmall || 'always'}
+                                               >
+                                                       <option value="never">
+                                                               {t('tracker.config.showItemOptions.never')}
+                                                       </option>
+                                                       <option value="situational">
+                                                               {t('tracker.config.showItemOptions.situational')}
+                                                       </option>
+                                                       <option value="always">
+                                                               {t('tracker.config.showItemOptions.always')}
+                                                       </option>
+                                               </Form.Select>
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.showBig"
+                                       >
+                                               <Form.Label>{t('tracker.config.showBig')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="showBig"
+                                                       onChange={handleChange}
+                                                       value={config.showBig || 'always'}
+                                               >
+                                                       <option value="never">
+                                                               {t('tracker.config.showItemOptions.never')}
+                                                       </option>
+                                                       <option value="situational">
+                                                               {t('tracker.config.showItemOptions.situational')}
+                                                       </option>
+                                                       <option value="always">
+                                                               {t('tracker.config.showItemOptions.always')}
+                                                       </option>
+                                               </Form.Select>
+                                       </Form.Group>
+                               </Col>
+                       </Row>
+                       <Row>
+                               <Col sm={6}>
+                                       <h3>{t('tracker.config.layout')}</h3>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.mapLayout"
+                                       >
+                                               <Form.Label>{t('tracker.config.mapLayout')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="mapLayout"
+                                                       onChange={handleChange}
+                                                       value={getConfigValue(config, 'mapLayout', 'horizontal')}
+                                               >
+                                                       {['horizontal', 'vertical'].map(n =>
+                                                               <option key={n} value={n}>
+                                                                       {t(`tracker.config.mapLayouts.${n}`)}
+                                                               </option>
+                                                       )}
+                                               </Form.Select>
+                                       </Form.Group>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.compactKeysanity"
+                                       >
+                                               <Form.Label>{t('tracker.config.compactKeysanity')}</Form.Label>
+                                               <Form.Control
+                                                       as={LargeCheck}
+                                                       name="compactKeysanity"
+                                                       onChange={handleChange}
+                                                       value={!!config.compactKeysanity}
+                                               />
+                                       </Form.Group>
+                               </Col>
+                               <Col sm={6}>
+                                       <h3>{t('tracker.config.calculation')}</h3>
+                                       <Form.Group
+                                               className="d-flex justify-content-between my-2"
+                                               controlId="tracker.checkCalculation"
+                                       >
+                                               <Form.Label>{t('tracker.config.checkCalculation')}</Form.Label>
+                                               <Form.Select
+                                                       className="w-auto"
+                                                       name="checkCalculation"
+                                                       onChange={handleChange}
+                                                       value={getConfigValue(config, 'checkCalculation', 'room-data')}
+                                               >
+                                                       {['inventory', 'room-data'].map(n =>
+                                                               <option key={n} value={n}>
+                                                                       {t(`tracker.config.checkCalculations.${n}`)}
+                                                               </option>
+                                                       )}
+                                               </Form.Select>
+                                       </Form.Group>
+                               </Col>
+                       </Row>
+               </Modal.Body>
+       </Modal>;
+};
+
+ConfigDialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+};
+
+export default ConfigDialog;
diff --git a/resources/js/components/tracker/CountDisplay.js b/resources/js/components/tracker/CountDisplay.js
deleted file mode 100644 (file)
index ba41b9f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-const CountDisplay = ({ className, count, full }) => {
-       const classNames = ['count-display'];
-       if (className) {
-               classNames.push(className);
-       }
-       if (!count) {
-               classNames.push('is-zero');
-       }
-       if (full && count >= full) {
-               classNames.push('is-full');
-       }
-       return <text className={classNames.join(' ')}>
-               {count}
-       </text>;
-};
-
-CountDisplay.propTypes = {
-       className: PropTypes.string,
-       count: PropTypes.number,
-       full: PropTypes.number,
-};
-
-export default CountDisplay;
diff --git a/resources/js/components/tracker/CountDisplay.jsx b/resources/js/components/tracker/CountDisplay.jsx
new file mode 100644 (file)
index 0000000..ba41b9f
--- /dev/null
@@ -0,0 +1,26 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+const CountDisplay = ({ className, count, full }) => {
+       const classNames = ['count-display'];
+       if (className) {
+               classNames.push(className);
+       }
+       if (!count) {
+               classNames.push('is-zero');
+       }
+       if (full && count >= full) {
+               classNames.push('is-full');
+       }
+       return <text className={classNames.join(' ')}>
+               {count}
+       </text>;
+};
+
+CountDisplay.propTypes = {
+       className: PropTypes.string,
+       count: PropTypes.number,
+       full: PropTypes.number,
+};
+
+export default CountDisplay;
diff --git a/resources/js/components/tracker/Dungeons.js b/resources/js/components/tracker/Dungeons.js
deleted file mode 100644 (file)
index 8a7e4d0..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import CountDisplay from './CountDisplay';
-import ToggleIcon from './ToggleIcon';
-import {
-       BOSSES,
-       getDungeonAcquiredSKs,
-       getDungeonRemainingItems,
-       shouldCompactKeysanity,
-       shouldShowDungeonItem,
-} from '../../helpers/tracker';
-import { useTracker } from '../../hooks/tracker';
-
-const Dungeons = ({ columns }) => {
-       const { config, dungeons, state } = useTracker();
-
-       const layout = React.useMemo(() => {
-               const compact = shouldCompactKeysanity(config);
-               const mapX = 1;
-               const compassX = shouldShowDungeonItem(config, 'Map') ? mapX + 1 : mapX;
-               const smallX = shouldShowDungeonItem(config, 'Compass') ? compassX + 1 : compassX;
-               const bigX =  shouldShowDungeonItem(config, 'Small') ? smallX + 1 : smallX;
-               const countX = compact ? 2 : shouldShowDungeonItem(config, 'Big') ? bigX + 1 : bigX;
-               const bossX = countX + 1;
-               const prizeX = bossX + 1;
-               const dungeonWidth = Math.max(5, prizeX + 1);
-               const width = (columns * dungeonWidth) + Math.max(0, columns - 1);
-               const height = 4;
-
-               const transform = (col, row) =>
-                       `scale(${1 / width}) translate(${
-                               (col * dungeonWidth) + 0.5 + (col ? col - (columns > 3 ? 1 : 0) : 0)
-                       } ${row + 0.5})`;
-
-               const transforms = {
-                       tag: null,
-                       map: compact
-                               ? 'translate(0.75 -0.25) scale(0.45)' : `translate(${mapX} 0) scale(0.9)`,
-                       compass: compact
-                               ? 'translate(1.25 -0.25) scale(0.45)' : `translate(${compassX} 0) scale(0.9)`,
-                       small: compact
-                               ? 'translate(0.75 0.25) scale(0.45)' : `translate(${smallX} 0) scale(0.9)`,
-                       big: compact
-                               ? 'translate(1.25 0.25) scale(0.45)' : `translate(${bigX} 0) scale(0.9)`,
-                       checks: `translate(${countX} 0) scale(0.9)`,
-                       boss: `translate(${bossX} 0)`,
-                       prize: `translate(${prizeX} 0)`,
-                       hc: transform(0, 0),
-                       ct: transform(0, 1),
-                       gt: transform(0, 2),
-                       gtBoss1: `translate(${bossX - 2} 1)`,
-                       gtBoss2: `translate(${bossX - 1} 1)`,
-                       gtBoss3: `translate(${bossX} 1)`,
-               };
-
-               if (columns === 1) {
-                       transforms.ep = transform(0, 4);
-                       transforms.dp = transform(0, 5);
-                       transforms.th = transform(0, 6);
-                       transforms.pd = transform(0, 8);
-                       transforms.sp = transform(0, 9);
-                       transforms.sw = transform(0, 10);
-                       transforms.tt = transform(0, 11);
-                       transforms.ip = transform(0, 12);
-                       transforms.mm = transform(0, 13);
-                       transforms.tr = transform(0, 14);
-               } else if (columns === 2) {
-                       transforms.ep = transform(0, 4);
-                       transforms.dp = transform(0, 5);
-                       transforms.th = transform(0, 6);
-                       transforms.pd = transform(1, 0);
-                       transforms.sp = transform(1, 1);
-                       transforms.sw = transform(1, 2);
-                       transforms.tt = transform(1, 3);
-                       transforms.ip = transform(1, 4);
-                       transforms.mm = transform(1, 5);
-                       transforms.tr = transform(1, 6);
-               } else {
-                       transforms.ep = transform(1, 0);
-                       transforms.dp = transform(1, 1);
-                       transforms.th = transform(1, 2);
-                       transforms.pd = transform(2, 0);
-                       transforms.sp = transform(2, 1);
-                       transforms.sw = transform(2, 2);
-                       transforms.tt = transform(2, 3);
-                       transforms.ip = transform(3, 0);
-                       transforms.mm = transform(3, 1);
-                       transforms.tr = transform(3, 2);
-               }
-
-               return {
-                       width,
-                       height,
-                       transforms,
-               };
-       }, [config, dungeons]);
-
-       return <>
-               {dungeons.map(dungeon =>
-                       <g
-                               className={`dungeon dungeon-${dungeon.id}`}
-                               key={dungeon.id}
-                               transform={layout.transforms[dungeon.id]}
-                       >
-                               <g transform={layout.transforms.tag}>
-                                       <text className="dungeon-tag">{dungeon.id.toUpperCase()}</text>
-                               </g>
-                               {shouldShowDungeonItem(config, 'Map') ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonController(dungeon)}
-                                               icons={['map']}
-                                               svg
-                                               transform={layout.transforms.map}
-                                       />
-                               : null}
-                               {shouldShowDungeonItem(config, 'Compass') ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonController(dungeon)}
-                                               icons={['compass']}
-                                               svg
-                                               transform={layout.transforms.compass}
-                                       />
-                               : null}
-                               {shouldShowDungeonItem(config, 'Small') ?
-                                       <g transform={layout.transforms.small}>
-                                               <ToggleIcon
-                                                       controller={ToggleIcon.dungeonCountController(dungeon, dungeon.sk)}
-                                                       icons={['small-key']}
-                                                       svg
-                                               />
-                                               <CountDisplay
-                                                       count={getDungeonAcquiredSKs(state, dungeon)}
-                                                       full={dungeon.sk}
-                                               />
-                                       </g>
-                               : null}
-                               {shouldShowDungeonItem(config, 'Big') ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonController(dungeon)}
-                                               icons={['big-key']}
-                                               svg
-                                               transform={layout.transforms.big}
-                                       />
-                               : null}
-                               <g transform={layout.transforms.checks}>
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonCheckController(dungeon)}
-                                               icons={['open-chest', 'chest']}
-                                               svg
-                                       />
-                                       <CountDisplay count={getDungeonRemainingItems(state, dungeon)} />
-                               </g>
-                               {dungeon.boss ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonBossController(dungeon)}
-                                               icons={dungeon.bosses}
-                                               svg
-                                               transform={layout.transforms.boss}
-                                       />
-                               : null}
-                               {dungeon.prize ?
-                                       <ToggleIcon
-                                               controller={ToggleIcon.dungeonPrizeController(dungeon)}
-                                               icons={[
-                                                       'crystal',
-                                                       'red-crystal',
-                                                       'green-pendant',
-                                                       'red-pendant',
-                                               ]}
-                                               svg
-                                               transform={layout.transforms.prize}
-                                       />
-                               : null}
-                               {dungeon.id === 'gt' && config.bossShuffle ? <>
-                                       <ToggleIcon
-                                               controller={ToggleIcon.gtBossController('bot')}
-                                               icons={BOSSES}
-                                               svg
-                                               transform={layout.transforms.gtBoss1}
-                                       />
-                                       <ToggleIcon
-                                               controller={ToggleIcon.gtBossController('mid')}
-                                               icons={BOSSES}
-                                               svg
-                                               transform={layout.transforms.gtBoss2}
-                                       />
-                                       <ToggleIcon
-                                               controller={ToggleIcon.gtBossController('top')}
-                                               icons={BOSSES}
-                                               svg
-                                               transform={layout.transforms.gtBoss3}
-                                       />
-                               </> : null}
-                       </g>
-               )}
-       </>;
-};
-
-Dungeons.propTypes = {
-       columns: PropTypes.number,
-};
-
-Dungeons.defaultProps = {
-       columns: 4,
-};
-
-export default Dungeons;
diff --git a/resources/js/components/tracker/Dungeons.jsx b/resources/js/components/tracker/Dungeons.jsx
new file mode 100644 (file)
index 0000000..758935c
--- /dev/null
@@ -0,0 +1,204 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import CountDisplay from './CountDisplay';
+import ToggleIcon from './ToggleIcon';
+import {
+       BOSSES,
+       getDungeonAcquiredSKs,
+       getDungeonRemainingItems,
+       shouldCompactKeysanity,
+       shouldShowDungeonItem,
+} from '../../helpers/tracker';
+import { useTracker } from '../../hooks/tracker';
+
+const Dungeons = ({ columns = 4 }) => {
+       const { config, dungeons, state } = useTracker();
+
+       const layout = React.useMemo(() => {
+               const compact = shouldCompactKeysanity(config);
+               const mapX = 1;
+               const compassX = shouldShowDungeonItem(config, 'Map') ? mapX + 1 : mapX;
+               const smallX = shouldShowDungeonItem(config, 'Compass') ? compassX + 1 : compassX;
+               const bigX =  shouldShowDungeonItem(config, 'Small') ? smallX + 1 : smallX;
+               const countX = compact ? 2 : shouldShowDungeonItem(config, 'Big') ? bigX + 1 : bigX;
+               const bossX = countX + 1;
+               const prizeX = bossX + 1;
+               const dungeonWidth = Math.max(5, prizeX + 1);
+               const width = (columns * dungeonWidth) + Math.max(0, columns - 1);
+               const height = 4;
+
+               const transform = (col, row) =>
+                       `scale(${1 / width}) translate(${
+                               (col * dungeonWidth) + 0.5 + (col ? col - (columns > 3 ? 1 : 0) : 0)
+                       } ${row + 0.5})`;
+
+               const transforms = {
+                       tag: null,
+                       map: compact
+                               ? 'translate(0.75 -0.25) scale(0.45)' : `translate(${mapX} 0) scale(0.9)`,
+                       compass: compact
+                               ? 'translate(1.25 -0.25) scale(0.45)' : `translate(${compassX} 0) scale(0.9)`,
+                       small: compact
+                               ? 'translate(0.75 0.25) scale(0.45)' : `translate(${smallX} 0) scale(0.9)`,
+                       big: compact
+                               ? 'translate(1.25 0.25) scale(0.45)' : `translate(${bigX} 0) scale(0.9)`,
+                       checks: `translate(${countX} 0) scale(0.9)`,
+                       boss: `translate(${bossX} 0)`,
+                       prize: `translate(${prizeX} 0)`,
+                       hc: transform(0, 0),
+                       ct: transform(0, 1),
+                       gt: transform(0, 2),
+                       gtBoss1: `translate(${bossX - 2} 1)`,
+                       gtBoss2: `translate(${bossX - 1} 1)`,
+                       gtBoss3: `translate(${bossX} 1)`,
+               };
+
+               if (columns === 1) {
+                       transforms.ep = transform(0, 4);
+                       transforms.dp = transform(0, 5);
+                       transforms.th = transform(0, 6);
+                       transforms.pd = transform(0, 8);
+                       transforms.sp = transform(0, 9);
+                       transforms.sw = transform(0, 10);
+                       transforms.tt = transform(0, 11);
+                       transforms.ip = transform(0, 12);
+                       transforms.mm = transform(0, 13);
+                       transforms.tr = transform(0, 14);
+               } else if (columns === 2) {
+                       transforms.ep = transform(0, 4);
+                       transforms.dp = transform(0, 5);
+                       transforms.th = transform(0, 6);
+                       transforms.pd = transform(1, 0);
+                       transforms.sp = transform(1, 1);
+                       transforms.sw = transform(1, 2);
+                       transforms.tt = transform(1, 3);
+                       transforms.ip = transform(1, 4);
+                       transforms.mm = transform(1, 5);
+                       transforms.tr = transform(1, 6);
+               } else {
+                       transforms.ep = transform(1, 0);
+                       transforms.dp = transform(1, 1);
+                       transforms.th = transform(1, 2);
+                       transforms.pd = transform(2, 0);
+                       transforms.sp = transform(2, 1);
+                       transforms.sw = transform(2, 2);
+                       transforms.tt = transform(2, 3);
+                       transforms.ip = transform(3, 0);
+                       transforms.mm = transform(3, 1);
+                       transforms.tr = transform(3, 2);
+               }
+
+               return {
+                       width,
+                       height,
+                       transforms,
+               };
+       }, [config, dungeons]);
+
+       return <>
+               {dungeons.map(dungeon =>
+                       <g
+                               className={`dungeon dungeon-${dungeon.id}`}
+                               key={dungeon.id}
+                               transform={layout.transforms[dungeon.id]}
+                       >
+                               <g transform={layout.transforms.tag}>
+                                       <text className="dungeon-tag">{dungeon.id.toUpperCase()}</text>
+                               </g>
+                               {shouldShowDungeonItem(config, 'Map') ?
+                                       <ToggleIcon
+                                               controller={ToggleIcon.dungeonController(dungeon)}
+                                               icons={['map']}
+                                               svg
+                                               transform={layout.transforms.map}
+                                       />
+                               : null}
+                               {shouldShowDungeonItem(config, 'Compass') ?
+                                       <ToggleIcon
+                                               controller={ToggleIcon.dungeonController(dungeon)}
+                                               icons={['compass']}
+                                               svg
+                                               transform={layout.transforms.compass}
+                                       />
+                               : null}
+                               {shouldShowDungeonItem(config, 'Small') ?
+                                       <g transform={layout.transforms.small}>
+                                               <ToggleIcon
+                                                       controller={ToggleIcon.dungeonCountController(dungeon, dungeon.sk)}
+                                                       icons={['small-key']}
+                                                       svg
+                                               />
+                                               <CountDisplay
+                                                       count={getDungeonAcquiredSKs(state, dungeon)}
+                                                       full={dungeon.sk}
+                                               />
+                                       </g>
+                               : null}
+                               {shouldShowDungeonItem(config, 'Big') ?
+                                       <ToggleIcon
+                                               controller={ToggleIcon.dungeonController(dungeon)}
+                                               icons={['big-key']}
+                                               svg
+                                               transform={layout.transforms.big}
+                                       />
+                               : null}
+                               <g transform={layout.transforms.checks}>
+                                       <ToggleIcon
+                                               controller={ToggleIcon.dungeonCheckController(dungeon)}
+                                               icons={['open-chest', 'chest']}
+                                               svg
+                                       />
+                                       <CountDisplay count={getDungeonRemainingItems(state, dungeon)} />
+                               </g>
+                               {dungeon.boss ?
+                                       <ToggleIcon
+                                               controller={ToggleIcon.dungeonBossController(dungeon)}
+                                               icons={dungeon.bosses}
+                                               svg
+                                               transform={layout.transforms.boss}
+                                       />
+                               : null}
+                               {dungeon.prize ?
+                                       <ToggleIcon
+                                               controller={ToggleIcon.dungeonPrizeController(dungeon)}
+                                               icons={[
+                                                       'crystal',
+                                                       'red-crystal',
+                                                       'green-pendant',
+                                                       'red-pendant',
+                                               ]}
+                                               svg
+                                               transform={layout.transforms.prize}
+                                       />
+                               : null}
+                               {dungeon.id === 'gt' && config.bossShuffle ? <>
+                                       <ToggleIcon
+                                               controller={ToggleIcon.gtBossController('bot')}
+                                               icons={BOSSES}
+                                               svg
+                                               transform={layout.transforms.gtBoss1}
+                                       />
+                                       <ToggleIcon
+                                               controller={ToggleIcon.gtBossController('mid')}
+                                               icons={BOSSES}
+                                               svg
+                                               transform={layout.transforms.gtBoss2}
+                                       />
+                                       <ToggleIcon
+                                               controller={ToggleIcon.gtBossController('top')}
+                                               icons={BOSSES}
+                                               svg
+                                               transform={layout.transforms.gtBoss3}
+                                       />
+                               </> : null}
+                       </g>
+               )}
+       </>;
+};
+
+Dungeons.propTypes = {
+       columns: PropTypes.number,
+};
+
+export default Dungeons;
diff --git a/resources/js/components/tracker/Equipment.js b/resources/js/components/tracker/Equipment.js
deleted file mode 100644 (file)
index 8877830..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-
-import ToggleIcon from './ToggleIcon';
-
-const Equipment = () => {
-       return <div className="equipment">
-               <div className="item">
-                       <ToggleIcon controller={ToggleIcon.simpleController} icons={['boots']} />
-               </div>
-               <div className="item">
-                       <ToggleIcon
-                               controller={ToggleIcon.progressiveController('lift', 0, 2)}
-                               icons={['glove', 'mitts']}
-                       />
-               </div>
-               <div className="item">
-                       <ToggleIcon controller={ToggleIcon.simpleController} icons={['flippers']} />
-               </div>
-               <div className="item">
-                       <ToggleIcon controller={ToggleIcon.simpleController} icons={['moonpearl']} />
-               </div>
-               <div className="item">
-                       <ToggleIcon
-                               controller={ToggleIcon.simpleController}
-                               icons={['half-magic', 'quarter-magic']}
-                       />
-               </div>
-               <div className="item">
-                       <ToggleIcon
-                               controller={ToggleIcon.progressiveController('sword', 0, 4)}
-                               icons={['sword-1', 'sword-2', 'sword-3', 'sword-4']}
-                       />
-               </div>
-               <div className="item">
-                       <ToggleIcon
-                               controller={ToggleIcon.progressiveController('shield', 0, 3)}
-                               icons={['fighter-shield', 'fire-shield', 'mirror-shield']}
-                       />
-               </div>
-               <div className="item">
-                       <ToggleIcon
-                               controller={ToggleIcon.progressiveController('mail', 1, 3)}
-                               icons={['green-mail', 'blue-mail', 'red-mail']}
-                       />
-               </div>
-               <div className="item">
-                       <ToggleIcon
-                               controller={ToggleIcon.modulusController('heart-piece')}
-                               icons={['heart-0', 'heart-1', 'heart-2', 'heart-3']}
-                       />
-               </div>
-       </div>;
-};
-
-export default Equipment;
diff --git a/resources/js/components/tracker/Equipment.jsx b/resources/js/components/tracker/Equipment.jsx
new file mode 100644 (file)
index 0000000..8877830
--- /dev/null
@@ -0,0 +1,55 @@
+import React from 'react';
+
+import ToggleIcon from './ToggleIcon';
+
+const Equipment = () => {
+       return <div className="equipment">
+               <div className="item">
+                       <ToggleIcon controller={ToggleIcon.simpleController} icons={['boots']} />
+               </div>
+               <div className="item">
+                       <ToggleIcon
+                               controller={ToggleIcon.progressiveController('lift', 0, 2)}
+                               icons={['glove', 'mitts']}
+                       />
+               </div>
+               <div className="item">
+                       <ToggleIcon controller={ToggleIcon.simpleController} icons={['flippers']} />
+               </div>
+               <div className="item">
+                       <ToggleIcon controller={ToggleIcon.simpleController} icons={['moonpearl']} />
+               </div>
+               <div className="item">
+                       <ToggleIcon
+                               controller={ToggleIcon.simpleController}
+                               icons={['half-magic', 'quarter-magic']}
+                       />
+               </div>
+               <div className="item">
+                       <ToggleIcon
+                               controller={ToggleIcon.progressiveController('sword', 0, 4)}
+                               icons={['sword-1', 'sword-2', 'sword-3', 'sword-4']}
+                       />
+               </div>
+               <div className="item">
+                       <ToggleIcon
+                               controller={ToggleIcon.progressiveController('shield', 0, 3)}
+                               icons={['fighter-shield', 'fire-shield', 'mirror-shield']}
+                       />
+               </div>
+               <div className="item">
+                       <ToggleIcon
+                               controller={ToggleIcon.progressiveController('mail', 1, 3)}
+                               icons={['green-mail', 'blue-mail', 'red-mail']}
+                       />
+               </div>
+               <div className="item">
+                       <ToggleIcon
+                               controller={ToggleIcon.modulusController('heart-piece')}
+                               icons={['heart-0', 'heart-1', 'heart-2', 'heart-3']}
+                       />
+               </div>
+       </div>;
+};
+
+export default Equipment;
diff --git a/resources/js/components/tracker/Items.js b/resources/js/components/tracker/Items.js
deleted file mode 100644 (file)
index e991d0b..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-import React from 'react';
-
-import ToggleIcon from './ToggleIcon';
-import { BOTTLE_CONTENTS } from '../../helpers/tracker';
-import { useTracker } from '../../hooks/tracker';
-
-const transform = (x, y, s) => `translate(${x * 0.2} ${y * 0.2}) scale(${(s || 0.85) * 0.2})`;
-
-const Items = () => {
-       const { state } = useTracker();
-
-       return <>
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['bow', 'silvers']}
-                       svg
-                       transform={transform(0.5, 0.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['blue-boomerang']}
-                       svg
-                       transform={transform(1.35, 0.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['red-boomerang']}
-                       svg
-                       transform={transform(1.85, 0.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['hookshot']}
-                       svg
-                       transform={transform(2.5, 0.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['bomb']}
-                       svg
-                       transform={transform(3.5, 0.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['powder']}
-                       svg
-                       transform={transform(4.5, 0.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['fire-rod']}
-                       svg
-                       transform={transform(0.5, 1.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['ice-rod']}
-                       svg
-                       transform={transform(1.5, 1.5)}
-               />
-               <g transform={transform(2.5, 1.5)}>
-                       <ToggleIcon controller={ToggleIcon.medallionController} icons={['bombos']} svg />
-                       {state['mm-medallion'] === 'bombos' ?
-                               <text className="med-display bottom-left">MM</text>
-                       : null}
-                       {state['tr-medallion'] === 'bombos' ?
-                               <text className="med-display bottom-right">TR</text>
-                       : null}
-               </g>
-               <g transform={transform(3.5, 1.5)}>
-                       <ToggleIcon controller={ToggleIcon.medallionController} icons={['ether']} svg />
-                       {state['mm-medallion'] === 'ether' ?
-                               <text className="med-display bottom-left">MM</text>
-                       : null}
-                       {state['tr-medallion'] === 'ether' ?
-                               <text className="med-display bottom-right">TR</text>
-                       : null}
-               </g>
-               <g transform={transform(4.5, 1.5)}>
-                       <ToggleIcon controller={ToggleIcon.medallionController} icons={['quake']} svg />
-                       {state['mm-medallion'] === 'quake' ?
-                               <text className="med-display bottom-left">MM</text>
-                       : null}
-                       {state['tr-medallion'] === 'quake' ?
-                               <text className="med-display bottom-right">TR</text>
-                       : null}
-               </g>
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['lamp']}
-                       svg
-                       transform={transform(0.5, 2.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['hammer']}
-                       svg
-                       transform={transform(1.5, 2.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['flute']}
-                       svg
-                       transform={transform(2.5, 2.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['duck']}
-                       svg
-                       transform={transform(2.75, 2.75, 0.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['bugnet']}
-                       svg
-                       transform={transform(3.5, 2.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['book']}
-                       svg
-                       transform={transform(4.5, 2.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['shovel']}
-                       svg
-                       transform={transform(0.5, 3.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['somaria']}
-                       svg
-                       transform={transform(1.5, 3.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['byrna']}
-                       svg
-                       transform={transform(2.5, 3.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['cape']}
-                       svg
-                       transform={transform(3.5, 3.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['mirror']}
-                       svg
-                       transform={transform(4.5, 3.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.bottleController('bottle-1')}
-                       icons={BOTTLE_CONTENTS}
-                       svg
-                       transform={transform(0.5, 5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.bottleController('bottle-2')}
-                       icons={BOTTLE_CONTENTS}
-                       svg
-                       transform={transform(1.5, 5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.bottleController('bottle-3')}
-                       icons={BOTTLE_CONTENTS}
-                       svg
-                       transform={transform(2.5, 5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.bottleController('bottle-4')}
-                       icons={BOTTLE_CONTENTS}
-                       svg
-                       transform={transform(3.5, 5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['mushroom']}
-                       svg
-                       transform={transform(4.5, 5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['boots']}
-                       svg
-                       transform={transform(0.5, 6.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.progressiveController('lift', 0, 2)}
-                       icons={['glove', 'mitts']}
-                       svg
-                       transform={transform(1.5, 6.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['flippers']}
-                       svg
-                       transform={transform(2.5, 6.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['moonpearl']}
-                       svg
-                       transform={transform(3.5, 6.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.simpleController}
-                       icons={['half-magic', 'quarter-magic']}
-                       svg
-                       transform={transform(4.5, 6.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.progressiveController('sword', 0, 4)}
-                       icons={['sword-1', 'sword-2', 'sword-3', 'sword-4']}
-                       svg
-                       transform={transform(0.5, 7.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.progressiveController('shield', 0, 3)}
-                       icons={['fighter-shield', 'fire-shield', 'mirror-shield']}
-                       svg
-                       transform={transform(1.5, 7.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.progressiveController('mail', 1, 3)}
-                       icons={['green-mail', 'blue-mail', 'red-mail']}
-                       svg
-                       transform={transform(2.5, 7.5)}
-               />
-               <ToggleIcon
-                       controller={ToggleIcon.modulusController('heart-piece')}
-                       icons={['heart-0', 'heart-1', 'heart-2', 'heart-3']}
-                       svg
-                       transform={transform(3.5, 7.5)}
-               />
-       </>;
-};
-
-export default Items;
diff --git a/resources/js/components/tracker/Items.jsx b/resources/js/components/tracker/Items.jsx
new file mode 100644 (file)
index 0000000..e991d0b
--- /dev/null
@@ -0,0 +1,241 @@
+import React from 'react';
+
+import ToggleIcon from './ToggleIcon';
+import { BOTTLE_CONTENTS } from '../../helpers/tracker';
+import { useTracker } from '../../hooks/tracker';
+
+const transform = (x, y, s) => `translate(${x * 0.2} ${y * 0.2}) scale(${(s || 0.85) * 0.2})`;
+
+const Items = () => {
+       const { state } = useTracker();
+
+       return <>
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['bow', 'silvers']}
+                       svg
+                       transform={transform(0.5, 0.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['blue-boomerang']}
+                       svg
+                       transform={transform(1.35, 0.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['red-boomerang']}
+                       svg
+                       transform={transform(1.85, 0.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['hookshot']}
+                       svg
+                       transform={transform(2.5, 0.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['bomb']}
+                       svg
+                       transform={transform(3.5, 0.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['powder']}
+                       svg
+                       transform={transform(4.5, 0.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['fire-rod']}
+                       svg
+                       transform={transform(0.5, 1.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['ice-rod']}
+                       svg
+                       transform={transform(1.5, 1.5)}
+               />
+               <g transform={transform(2.5, 1.5)}>
+                       <ToggleIcon controller={ToggleIcon.medallionController} icons={['bombos']} svg />
+                       {state['mm-medallion'] === 'bombos' ?
+                               <text className="med-display bottom-left">MM</text>
+                       : null}
+                       {state['tr-medallion'] === 'bombos' ?
+                               <text className="med-display bottom-right">TR</text>
+                       : null}
+               </g>
+               <g transform={transform(3.5, 1.5)}>
+                       <ToggleIcon controller={ToggleIcon.medallionController} icons={['ether']} svg />
+                       {state['mm-medallion'] === 'ether' ?
+                               <text className="med-display bottom-left">MM</text>
+                       : null}
+                       {state['tr-medallion'] === 'ether' ?
+                               <text className="med-display bottom-right">TR</text>
+                       : null}
+               </g>
+               <g transform={transform(4.5, 1.5)}>
+                       <ToggleIcon controller={ToggleIcon.medallionController} icons={['quake']} svg />
+                       {state['mm-medallion'] === 'quake' ?
+                               <text className="med-display bottom-left">MM</text>
+                       : null}
+                       {state['tr-medallion'] === 'quake' ?
+                               <text className="med-display bottom-right">TR</text>
+                       : null}
+               </g>
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['lamp']}
+                       svg
+                       transform={transform(0.5, 2.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['hammer']}
+                       svg
+                       transform={transform(1.5, 2.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['flute']}
+                       svg
+                       transform={transform(2.5, 2.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['duck']}
+                       svg
+                       transform={transform(2.75, 2.75, 0.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['bugnet']}
+                       svg
+                       transform={transform(3.5, 2.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['book']}
+                       svg
+                       transform={transform(4.5, 2.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['shovel']}
+                       svg
+                       transform={transform(0.5, 3.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['somaria']}
+                       svg
+                       transform={transform(1.5, 3.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['byrna']}
+                       svg
+                       transform={transform(2.5, 3.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['cape']}
+                       svg
+                       transform={transform(3.5, 3.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['mirror']}
+                       svg
+                       transform={transform(4.5, 3.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.bottleController('bottle-1')}
+                       icons={BOTTLE_CONTENTS}
+                       svg
+                       transform={transform(0.5, 5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.bottleController('bottle-2')}
+                       icons={BOTTLE_CONTENTS}
+                       svg
+                       transform={transform(1.5, 5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.bottleController('bottle-3')}
+                       icons={BOTTLE_CONTENTS}
+                       svg
+                       transform={transform(2.5, 5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.bottleController('bottle-4')}
+                       icons={BOTTLE_CONTENTS}
+                       svg
+                       transform={transform(3.5, 5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['mushroom']}
+                       svg
+                       transform={transform(4.5, 5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['boots']}
+                       svg
+                       transform={transform(0.5, 6.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.progressiveController('lift', 0, 2)}
+                       icons={['glove', 'mitts']}
+                       svg
+                       transform={transform(1.5, 6.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['flippers']}
+                       svg
+                       transform={transform(2.5, 6.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['moonpearl']}
+                       svg
+                       transform={transform(3.5, 6.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.simpleController}
+                       icons={['half-magic', 'quarter-magic']}
+                       svg
+                       transform={transform(4.5, 6.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.progressiveController('sword', 0, 4)}
+                       icons={['sword-1', 'sword-2', 'sword-3', 'sword-4']}
+                       svg
+                       transform={transform(0.5, 7.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.progressiveController('shield', 0, 3)}
+                       icons={['fighter-shield', 'fire-shield', 'mirror-shield']}
+                       svg
+                       transform={transform(1.5, 7.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.progressiveController('mail', 1, 3)}
+                       icons={['green-mail', 'blue-mail', 'red-mail']}
+                       svg
+                       transform={transform(2.5, 7.5)}
+               />
+               <ToggleIcon
+                       controller={ToggleIcon.modulusController('heart-piece')}
+                       icons={['heart-0', 'heart-1', 'heart-2', 'heart-3']}
+                       svg
+                       transform={transform(3.5, 7.5)}
+               />
+       </>;
+};
+
+export default Items;
diff --git a/resources/js/components/tracker/Map/Overworld.js b/resources/js/components/tracker/Map/Overworld.js
deleted file mode 100644 (file)
index f899593..0000000
+++ /dev/null
@@ -1,880 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-import {
-       addDungeonCheck,
-       aggregateDungeonStatus,
-       aggregateLocationStatus,
-       clearAll,
-       completeDungeonChecks,
-       countRemainingLocations,
-       getDungeonClearedItems,
-       getDungeonRemainingItems,
-       hasDungeonBoss,
-       hasDungeonPrize,
-       isDungeonCleared,
-       removeDungeonCheck,
-       resetDungeonChecks,
-       setBossDefeated,
-       setPrizeAcquired,
-       unclearAll,
-} from '../../../helpers/tracker';
-import { useTracker } from '../../../hooks/tracker';
-
-const GENERIC_LW_DUNGEONS = [
-       {
-               id: 'hc',
-               x: 0.5,
-               y: 0.5,
-       },
-       {
-               id: 'ep',
-               x: 0.95,
-               y: 0.42,
-       },
-       {
-               id: 'dp',
-               x: 0.075,
-               y: 0.8,
-       },
-       {
-               id: 'th',
-               x: 0.56,
-               y: 0.05,
-       },
-];
-
-const LW_DUNGEONS = [
-       ...GENERIC_LW_DUNGEONS,
-       {
-               id: 'ct',
-               x: 0.5,
-               y: 0.4,
-       },
-];
-
-const INVERTED_LW_DUNGEONS = [
-       ...GENERIC_LW_DUNGEONS,
-       {
-               id: 'gt',
-               x: 0.5,
-               y: 0.4,
-       },
-];
-
-const GENERIC_LW_LOCATIONS = [
-       {
-               id: 'aginah',
-               checks: [
-                       'aginah',
-               ],
-               x: 0.2,
-               y: 0.83,
-       },
-       {
-               id: 'blinds-hut',
-               checks: [
-                       'blinds-hut-top',
-                       'blinds-hut-left',
-                       'blinds-hut-right',
-                       'blinds-hut-far-left',
-                       'blinds-hut-far-right',
-               ],
-               x: 0.14,
-               y: 0.42,
-       },
-       {
-               id: 'bombos-tablet',
-               checks: [
-                       'bombos-tablet',
-               ],
-               x: 0.225,
-               y: 0.925,
-       },
-       {
-               id: 'bonk-rocks',
-               checks: [
-                       'bonk-rocks',
-               ],
-               x: 0.4,
-               y: 0.3,
-       },
-       {
-               id: 'bottle-vendor',
-               checks: [
-                       'bottle-vendor',
-               ],
-               x: 0.1,
-               y: 0.475,
-       },
-       {
-               id: 'cave-45',
-               checks: [
-                       'cave-45',
-               ],
-               x: 0.27,
-               y: 0.83,
-       },
-       {
-               id: 'checkerboard',
-               checks: [
-                       'checkerboard',
-               ],
-               x: 0.18,
-               y: 0.78,
-       },
-       {
-               id: 'chicken-house',
-               checks: [
-                       'chicken-house',
-               ],
-               x: 0.1,
-               y: 0.53,
-       },
-       {
-               id: 'dam',
-               checks: [
-                       'flooded-chest',
-                       'sunken-treasure',
-               ],
-               x: 0.4675,
-               y: 0.9375,
-       },
-       {
-               id: 'desert-ledge',
-               checks: [
-                       'desert-ledge',
-               ],
-               x: 0.025,
-               y: 0.9,
-       },
-       {
-               id: 'ether-tablet',
-               checks: [
-                       'ether-tablet',
-               ],
-               x: 0.425,
-               y: 0.025,
-       },
-       {
-               id: 'floating-island',
-               checks: [
-                       'floating-island',
-               ],
-               x: 0.8,
-               y: 0.025,
-       },
-       {
-               id: 'flute-spot',
-               checks: [
-                       'flute-spot',
-               ],
-               x: 0.3,
-               y: 0.675,
-       },
-       {
-               id: 'graveyard-ledge',
-               checks: [
-                       'graveyard-ledge',
-               ],
-               x: 0.57,
-               y: 0.28,
-       },
-       {
-               id: 'hobo',
-               checks: [
-                       'hobo',
-               ],
-               x: 0.7,
-               y: 0.7,
-       },
-       {
-               id: 'ice-rod-cave',
-               checks: [
-                       'ice-rod-cave',
-               ],
-               x: 0.9,
-               y: 0.76,
-       },
-       {
-               id: 'kak-well',
-               checks: [
-                       'kak-well-top',
-                       'kak-well-left',
-                       'kak-well-mid',
-                       'kak-well-right',
-                       'kak-well-bottom',
-               ],
-               x: 0.04,
-               y: 0.425,
-       },
-       {
-               id: 'kings-tomb',
-               checks: [
-                       'kings-tomb',
-               ],
-               x: 0.62,
-               y: 0.3,
-       },
-       {
-               id: 'lake-hylia-island',
-               checks: [
-                       'lake-hylia-island',
-               ],
-               x: 0.725,
-               y: 0.8375,
-       },
-       {
-               id: 'library',
-               checks: [
-                       'library',
-               ],
-               x: 0.15,
-               y: 0.65,
-       },
-       {
-               id: 'lost-woods-hideout',
-               checks: [
-                       'lost-woods-hideout',
-               ],
-               x: 0.19,
-               y: 0.14,
-       },
-       {
-               id: 'lumberjack',
-               checks: [
-                       'lumberjack',
-               ],
-               x: 0.3,
-               y: 0.07,
-       },
-       {
-               id: 'magic-bat',
-               checks: [
-                       'magic-bat',
-               ],
-               x: 0.325,
-               y: 0.55,
-       },
-       {
-               id: 'mimic-cave',
-               checks: [
-                       'mimic-cave',
-               ],
-               x: 0.85,
-               y: 0.1,
-       },
-       {
-               id: 'mini-moldorm-cave',
-               checks: [
-                       'mini-moldorm-left',
-                       'mini-moldorm-right',
-                       'mini-moldorm-far-left',
-                       'mini-moldorm-far-right',
-                       'mini-moldorm-npc',
-               ],
-               x: 0.65,
-               y: 0.95,
-       },
-       {
-               id: 'mushroom-spot',
-               checks: [
-                       'mushroom-spot',
-               ],
-               x: 0.125,
-               y: 0.08,
-       },
-       {
-               id: 'old-man',
-               checks: [
-                       'old-man',
-               ],
-               x: 0.405,
-               y: 0.195,
-       },
-       {
-               id: 'paradox-cave',
-               checks: [
-                       'paradox-lower-far-left',
-                       'paradox-lower-left',
-                       'paradox-lower-right',
-                       'paradox-lower-far-right',
-                       'paradox-lower-mid',
-                       'paradox-upper-left',
-                       'paradox-upper-right',
-               ],
-               x: 0.85,
-               y: 0.2,
-       },
-       {
-               id: 'pedestal',
-               checks: [
-                       'pedestal',
-               ],
-               x: 0.03,
-               y: 0.05,
-       },
-       {
-               id: 'potion-shop',
-               checks: [
-                       'potion-shop',
-               ],
-               x: 0.8,
-               y: 0.325,
-       },
-       {
-               id: 'race-game',
-               checks: [
-                       'race-game',
-               ],
-               x: 0.025,
-               y: 0.7,
-       },
-       {
-               id: 'saha',
-               checks: [
-                       'saha',
-               ],
-               x: 0.815,
-               y: 0.465,
-       },
-       {
-               id: 'saha-hut',
-               checks: [
-                       'saha-left',
-                       'saha-mid',
-                       'saha-right',
-               ],
-               x: 0.815,
-               y: 0.42,
-       },
-       {
-               id: 'sick-kid',
-               checks: [
-                       'sick-kid',
-               ],
-               x: 0.155,
-               y: 0.525,
-       },
-       {
-               id: 'uncle',
-               checks: [
-                       'uncle',
-                       'secret-passage',
-               ],
-               x: 0.6,
-               y: 0.4,
-       },
-       {
-               id: 'spec-rock',
-               checks: [
-                       'spec-rock',
-               ],
-               x: 0.48,
-               y: 0.09,
-       },
-       {
-               id: 'spec-rock-cave',
-               checks: [
-                       'spec-rock-cave',
-               ],
-               x: 0.48,
-               y: 0.14,
-       },
-       {
-               id: 'spiral-cave',
-               checks: [
-                       'spiral-cave',
-               ],
-               x: 0.8,
-               y: 0.1,
-       },
-       {
-               id: 'tavern',
-               checks: [
-                       'tavern',
-               ],
-               x: 0.16,
-               y: 0.58,
-       },
-       {
-               id: 'waterfall-fairy',
-               checks: [
-                       'waterfall-fairy-left',
-                       'waterfall-fairy-right',
-               ],
-               x: 0.9,
-               y: 0.15,
-       },
-       {
-               id: 'zora',
-               checks: [
-                       'zora',
-               ],
-               x: 0.975,
-               y: 0.12,
-       },
-       {
-               id: 'zora-ledge',
-               checks: [
-                       'zora-ledge',
-               ],
-               x: 0.975,
-               y: 0.165,
-       },
-];
-
-const LW_LOCATIONS = [
-       ...GENERIC_LW_LOCATIONS,
-       {
-               id: 'links-house',
-               checks: [
-                       'links-house',
-               ],
-               x: 0.55,
-               y: 0.6875,
-       },
-];
-
-const INVERTED_LW_LOCATIONS = GENERIC_LW_LOCATIONS;
-
-const GENERIC_DW_DUNGEONS = [
-       {
-               id: 'pd',
-               x: 0.95,
-               y: 0.42,
-       },
-       {
-               id: 'sp',
-               x: 0.4675,
-               y: 0.9375,
-       },
-       {
-               id: 'sw',
-               x: 0.05,
-               y: 0.05,
-       },
-       {
-               id: 'tt',
-               x: 0.125,
-               y: 0.475,
-       },
-       {
-               id: 'ip',
-               x: 0.7975,
-               y: 0.86,
-       },
-       {
-               id: 'mm',
-               x: 0.12,
-               y: 0.82,
-       },
-       {
-               id: 'tr',
-               x: 0.94,
-               y: 0.06,
-       },
-];
-
-const DW_DUNGEONS = [
-       ...GENERIC_DW_DUNGEONS,
-       {
-               id: 'gt',
-               x: 0.56,
-               y: 0.05,
-       },
-];
-
-const INVERTED_DW_DUNGEONS = [
-       ...GENERIC_DW_DUNGEONS,
-       {
-               id: 'ct',
-               x: 0.56,
-               y: 0.05,
-       },
-];
-
-const GENERIC_DW_LOCATIONS = [
-       {
-               id: 'blacksmith',
-               checks: [
-                       'blacksmith',
-               ],
-               x: 0.15,
-               y: 0.65,
-       },
-       {
-               id: 'brewery',
-               checks: [
-                       'brewery',
-               ],
-               x: 0.1,
-               y: 0.6,
-       },
-       {
-               id: 'bumper-cave',
-               checks: [
-                       'bumper-cave',
-               ],
-               x: 0.325,
-               y: 0.15,
-       },
-       {
-               id: 'c-house',
-               checks: [
-                       'c-house',
-               ],
-               x: 0.2,
-               y: 0.5,
-       },
-       {
-               id: 'catfish',
-               checks: [
-                       'catfish',
-               ],
-               x: 0.9,
-               y: 0.175,
-       },
-       {
-               id: 'chest-game',
-               checks: [
-                       'chest-game',
-               ],
-               x: 0.05,
-               y: 0.45,
-       },
-       {
-               id: 'digging-game',
-               checks: [
-                       'digging-game',
-               ],
-               x: 0.05,
-               y: 0.7,
-       },
-       {
-               id: 'hammer-pegs',
-               checks: [
-                       'hammer-pegs',
-               ],
-               x: 0.3125,
-               y: 0.6,
-       },
-       {
-               id: 'hookshot-cave',
-               checks: [
-                       'hookshot-cave-tl',
-                       'hookshot-cave-tr',
-                       'hookshot-cave-bl',
-               ],
-               x: 0.85,
-               y: 0.02,
-       },
-       {
-               id: 'hookshot-cave-bonk',
-               checks: [
-                       'hookshot-cave-br',
-               ],
-               x: 0.85,
-               y: 0.065,
-       },
-       {
-               id: 'hype-cave',
-               checks: [
-                       'hype-cave-top',
-                       'hype-cave-left',
-                       'hype-cave-right',
-                       'hype-cave-bottom',
-                       'hype-cave-npc',
-               ],
-               x: 0.6,
-               y: 0.75,
-       },
-       {
-               id: 'mire-shed',
-               checks: [
-                       'mire-shed-left',
-                       'mire-shed-right',
-               ],
-               x: 0.04,
-               y: 0.8,
-       },
-       {
-               id: 'purple-chest',
-               checks: [
-                       'purple-chest',
-               ],
-               x: 0.3125,
-               y: 0.525,
-       },
-       {
-               id: 'pyramid',
-               checks: [
-                       'pyramid',
-               ],
-               x: 0.575,
-               y: 0.45,
-       },
-       {
-               id: 'pyramid-fairy',
-               checks: [
-                       'pyramid-fairy-left',
-                       'pyramid-fairy-right',
-               ],
-               x: 0.45,
-               y: 0.5,
-       },
-       {
-               id: 'spike-cave',
-               checks: [
-                       'spike-cave',
-               ],
-               x: 0.575,
-               y: 0.15,
-       },
-       {
-               id: 'stumpy',
-               checks: [
-                       'stumpy',
-               ],
-               x: 0.3125,
-               y: 0.6875,
-       },
-       {
-               id: 'super-bunny',
-               checks: [
-                       'super-bunny-top',
-                       'super-bunny-bottom',
-               ],
-               x: 0.85,
-               y: 0.15,
-       },
-];
-
-const DW_LOCATIONS = GENERIC_DW_LOCATIONS;
-
-const INVERTED_DW_LOCATIONS = [
-       ...GENERIC_DW_LOCATIONS,
-       {
-               id: 'links-house',
-               checks: [
-                       'links-house',
-               ],
-               x: 0.55,
-               y: 0.6875,
-       },
-];
-
-const Location = ({ number, l, size }) => {
-       const { t } = useTranslation();
-
-       const classNames = ['location', `status-${l.status}`];
-       if (size) {
-               classNames.push(`size-${size}`);
-       }
-       if (l.handlePrimary) {
-               classNames.push('clickable');
-       }
-
-       return <g
-               className={classNames.join(' ')}
-               onClick={(e) => {
-                       l.handlePrimary();
-                       e.preventDefault();
-                       e.stopPropagation();
-               }}
-               onContextMenu={(e) => {
-                       l.handleSecondary();
-                       e.preventDefault();
-                       e.stopPropagation();
-               }}
-               transform={`translate(${l.x} ${l.y})`}
-       >
-               <title>{t(`tracker.location.${l.id}`)}</title>
-               <rect className="box" x="0" y="0" />
-               {number && l.remaining ?
-                       <text className="text" x="0" y="0">{l.remaining}</text>
-               : null}
-       </g>;
-};
-
-Location.propTypes = {
-       number: PropTypes.bool,
-       l: PropTypes.shape({
-               id: PropTypes.string,
-               x: PropTypes.number,
-               y: PropTypes.number,
-               number: PropTypes.number,
-               remaining: PropTypes.number,
-               status: PropTypes.string,
-               handlePrimary: PropTypes.func,
-               handleSecondary: PropTypes.func,
-       }),
-       size: PropTypes.string,
-};
-
-const makeBackground = (src, level) => {
-       const amount = Math.pow(2, Math.max(0, level - 8));
-       const size = 1 / amount;
-       const tiles = [];
-       for (let y = 0; y < amount; ++y) {
-               for (let x = 0; x < amount; ++x) {
-                       tiles.push(<image
-                               key={`${x}-${y}`}
-                               x={x * size}
-                               y={y * size}
-                               width={size * 1.002}
-                               height={size * 1.002}
-                               href={`/media/alttp/map/${src}/${level}/${x}_${y}.png`}
-                       />);
-               }
-       }
-       return tiles;
-};
-
-const Overworld = () => {
-       const { config, dungeons, logic, setManualState, state } = useTracker();
-
-       const mapDungeon = React.useCallback(dungeon => {
-               const definition = dungeons.find(d => d.id === dungeon.id);
-               const remaining = getDungeonRemainingItems(state, definition);
-               const status = aggregateDungeonStatus(definition, logic, state);
-               return {
-                       ...dungeon,
-                       status,
-                       remaining,
-                       handlePrimary: () => {
-                               if (getDungeonRemainingItems(state, definition)) {
-                                       setManualState(addDungeonCheck(definition));
-                               } else if (
-                                       !hasDungeonBoss(state, definition) || !hasDungeonPrize(state, definition)
-                               ) {
-                                       if (definition.boss) {
-                                               setManualState(setBossDefeated(definition, true));
-                                       }
-                                       if (definition.prize) {
-                                               setManualState(setPrizeAcquired(definition, true));
-                                       }
-                               } else {
-                                       setManualState(resetDungeonChecks(definition));
-                                       if (definition.boss) {
-                                               setManualState(setBossDefeated(definition, false));
-                                       }
-                                       if (definition.prize) {
-                                               setManualState(setPrizeAcquired(definition, false));
-                                       }
-                               }
-                       },
-                       handleSecondary: () => {
-                               if (isDungeonCleared(state, definition)) {
-                                       if (definition.items) {
-                                               setManualState(removeDungeonCheck(definition));
-                                       }
-                                       if (definition.boss) {
-                                               setManualState(setBossDefeated(definition, false));
-                                       }
-                                       if (definition.prize) {
-                                               setManualState(setPrizeAcquired(definition, false));
-                                       }
-                               } else if (getDungeonClearedItems(state, definition)) {
-                                       setManualState(removeDungeonCheck(definition));
-                               } else {
-                                       setManualState(completeDungeonChecks(definition));
-                                       if (definition.boss) {
-                                               setManualState(setBossDefeated(definition, true));
-                                       }
-                                       if (definition.prize) {
-                                               setManualState(setPrizeAcquired(definition, true));
-                                       }
-                               }
-                       },
-               };
-       }, [dungeons, logic, setManualState, state]);
-
-       const mapLocation = React.useCallback(loc => {
-               const remaining = countRemainingLocations(state, loc.checks);
-               const status = aggregateLocationStatus(loc.checks, logic, state);
-               return {
-                       ...loc,
-                       remaining,
-                       status,
-                       handlePrimary: () => {
-                               if (remaining) {
-                                       setManualState(clearAll(loc.checks));
-                               } else {
-                                       setManualState(unclearAll(loc.checks));
-                               }
-                       },
-                       handleSecondary: () => {
-                               if (remaining) {
-                                       setManualState(clearAll(loc.checks));
-                               } else {
-                                       setManualState(unclearAll(loc.checks));
-                               }
-                       },
-               };
-       }, [logic, setManualState, state]);
-
-       const lwDungeons = React.useMemo(() =>
-               (config.worldState === 'inverted' ? INVERTED_LW_DUNGEONS : LW_DUNGEONS)
-               .map(mapDungeon)
-       , [mapDungeon]);
-       const lwLocations = React.useMemo(() =>
-               (config.worldState === 'inverted' ? INVERTED_LW_LOCATIONS : LW_LOCATIONS)
-               .map(mapLocation)
-       , [mapLocation]);
-
-       const dwDungeons = React.useMemo(() =>
-               (config.worldState === 'inverted' ? INVERTED_DW_DUNGEONS : DW_DUNGEONS)
-               .map(mapDungeon)
-       , [mapDungeon]);
-       const dwLocations = React.useMemo(() =>
-               (config.worldState === 'inverted' ? INVERTED_DW_LOCATIONS : DW_LOCATIONS)
-               .map(mapLocation)
-       , [mapLocation]);
-
-       const layout = React.useMemo(() => {
-               if (config.mapLayout === 'vertical') {
-                       return {
-                               lwTransform: '',
-                               dwTransform: 'translate(0 1)',
-                       };
-               } else {
-                       return {
-                               lwTransform: 'scale(0.5)',
-                               dwTransform: 'scale(0.5) translate(1 0)',
-                       };
-               }
-       }, [config]);
-
-       return <>
-               <g className="light-world" transform={layout.lwTransform}>
-                       <g className="background">
-                               {makeBackground('lw_files', 10)}
-                       </g>
-                       <g className="locations">
-                               {lwLocations.map(l =>
-                                       <Location key={l.id} l={l} />
-                               )}
-                               {lwDungeons.map(l =>
-                                       <Location key={l.id} number l={l} size="lg" />
-                               )}
-                       </g>
-               </g>
-               <g className="dark-world" transform={layout.dwTransform}>
-                       <g className="background">
-                               {makeBackground('dw_files', 10)}
-                       </g>
-                       <g className="locations">
-                               {dwLocations.map(l =>
-                                       <Location key={l.id} l={l} />
-                               )}
-                               {dwDungeons.map(l =>
-                                       <Location key={l.id} number l={l} size="lg" />
-                               )}
-                       </g>
-               </g>
-       </>;
-};
-
-export default Overworld;
diff --git a/resources/js/components/tracker/Map/Overworld.jsx b/resources/js/components/tracker/Map/Overworld.jsx
new file mode 100644 (file)
index 0000000..f899593
--- /dev/null
@@ -0,0 +1,880 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import {
+       addDungeonCheck,
+       aggregateDungeonStatus,
+       aggregateLocationStatus,
+       clearAll,
+       completeDungeonChecks,
+       countRemainingLocations,
+       getDungeonClearedItems,
+       getDungeonRemainingItems,
+       hasDungeonBoss,
+       hasDungeonPrize,
+       isDungeonCleared,
+       removeDungeonCheck,
+       resetDungeonChecks,
+       setBossDefeated,
+       setPrizeAcquired,
+       unclearAll,
+} from '../../../helpers/tracker';
+import { useTracker } from '../../../hooks/tracker';
+
+const GENERIC_LW_DUNGEONS = [
+       {
+               id: 'hc',
+               x: 0.5,
+               y: 0.5,
+       },
+       {
+               id: 'ep',
+               x: 0.95,
+               y: 0.42,
+       },
+       {
+               id: 'dp',
+               x: 0.075,
+               y: 0.8,
+       },
+       {
+               id: 'th',
+               x: 0.56,
+               y: 0.05,
+       },
+];
+
+const LW_DUNGEONS = [
+       ...GENERIC_LW_DUNGEONS,
+       {
+               id: 'ct',
+               x: 0.5,
+               y: 0.4,
+       },
+];
+
+const INVERTED_LW_DUNGEONS = [
+       ...GENERIC_LW_DUNGEONS,
+       {
+               id: 'gt',
+               x: 0.5,
+               y: 0.4,
+       },
+];
+
+const GENERIC_LW_LOCATIONS = [
+       {
+               id: 'aginah',
+               checks: [
+                       'aginah',
+               ],
+               x: 0.2,
+               y: 0.83,
+       },
+       {
+               id: 'blinds-hut',
+               checks: [
+                       'blinds-hut-top',
+                       'blinds-hut-left',
+                       'blinds-hut-right',
+                       'blinds-hut-far-left',
+                       'blinds-hut-far-right',
+               ],
+               x: 0.14,
+               y: 0.42,
+       },
+       {
+               id: 'bombos-tablet',
+               checks: [
+                       'bombos-tablet',
+               ],
+               x: 0.225,
+               y: 0.925,
+       },
+       {
+               id: 'bonk-rocks',
+               checks: [
+                       'bonk-rocks',
+               ],
+               x: 0.4,
+               y: 0.3,
+       },
+       {
+               id: 'bottle-vendor',
+               checks: [
+                       'bottle-vendor',
+               ],
+               x: 0.1,
+               y: 0.475,
+       },
+       {
+               id: 'cave-45',
+               checks: [
+                       'cave-45',
+               ],
+               x: 0.27,
+               y: 0.83,
+       },
+       {
+               id: 'checkerboard',
+               checks: [
+                       'checkerboard',
+               ],
+               x: 0.18,
+               y: 0.78,
+       },
+       {
+               id: 'chicken-house',
+               checks: [
+                       'chicken-house',
+               ],
+               x: 0.1,
+               y: 0.53,
+       },
+       {
+               id: 'dam',
+               checks: [
+                       'flooded-chest',
+                       'sunken-treasure',
+               ],
+               x: 0.4675,
+               y: 0.9375,
+       },
+       {
+               id: 'desert-ledge',
+               checks: [
+                       'desert-ledge',
+               ],
+               x: 0.025,
+               y: 0.9,
+       },
+       {
+               id: 'ether-tablet',
+               checks: [
+                       'ether-tablet',
+               ],
+               x: 0.425,
+               y: 0.025,
+       },
+       {
+               id: 'floating-island',
+               checks: [
+                       'floating-island',
+               ],
+               x: 0.8,
+               y: 0.025,
+       },
+       {
+               id: 'flute-spot',
+               checks: [
+                       'flute-spot',
+               ],
+               x: 0.3,
+               y: 0.675,
+       },
+       {
+               id: 'graveyard-ledge',
+               checks: [
+                       'graveyard-ledge',
+               ],
+               x: 0.57,
+               y: 0.28,
+       },
+       {
+               id: 'hobo',
+               checks: [
+                       'hobo',
+               ],
+               x: 0.7,
+               y: 0.7,
+       },
+       {
+               id: 'ice-rod-cave',
+               checks: [
+                       'ice-rod-cave',
+               ],
+               x: 0.9,
+               y: 0.76,
+       },
+       {
+               id: 'kak-well',
+               checks: [
+                       'kak-well-top',
+                       'kak-well-left',
+                       'kak-well-mid',
+                       'kak-well-right',
+                       'kak-well-bottom',
+               ],
+               x: 0.04,
+               y: 0.425,
+       },
+       {
+               id: 'kings-tomb',
+               checks: [
+                       'kings-tomb',
+               ],
+               x: 0.62,
+               y: 0.3,
+       },
+       {
+               id: 'lake-hylia-island',
+               checks: [
+                       'lake-hylia-island',
+               ],
+               x: 0.725,
+               y: 0.8375,
+       },
+       {
+               id: 'library',
+               checks: [
+                       'library',
+               ],
+               x: 0.15,
+               y: 0.65,
+       },
+       {
+               id: 'lost-woods-hideout',
+               checks: [
+                       'lost-woods-hideout',
+               ],
+               x: 0.19,
+               y: 0.14,
+       },
+       {
+               id: 'lumberjack',
+               checks: [
+                       'lumberjack',
+               ],
+               x: 0.3,
+               y: 0.07,
+       },
+       {
+               id: 'magic-bat',
+               checks: [
+                       'magic-bat',
+               ],
+               x: 0.325,
+               y: 0.55,
+       },
+       {
+               id: 'mimic-cave',
+               checks: [
+                       'mimic-cave',
+               ],
+               x: 0.85,
+               y: 0.1,
+       },
+       {
+               id: 'mini-moldorm-cave',
+               checks: [
+                       'mini-moldorm-left',
+                       'mini-moldorm-right',
+                       'mini-moldorm-far-left',
+                       'mini-moldorm-far-right',
+                       'mini-moldorm-npc',
+               ],
+               x: 0.65,
+               y: 0.95,
+       },
+       {
+               id: 'mushroom-spot',
+               checks: [
+                       'mushroom-spot',
+               ],
+               x: 0.125,
+               y: 0.08,
+       },
+       {
+               id: 'old-man',
+               checks: [
+                       'old-man',
+               ],
+               x: 0.405,
+               y: 0.195,
+       },
+       {
+               id: 'paradox-cave',
+               checks: [
+                       'paradox-lower-far-left',
+                       'paradox-lower-left',
+                       'paradox-lower-right',
+                       'paradox-lower-far-right',
+                       'paradox-lower-mid',
+                       'paradox-upper-left',
+                       'paradox-upper-right',
+               ],
+               x: 0.85,
+               y: 0.2,
+       },
+       {
+               id: 'pedestal',
+               checks: [
+                       'pedestal',
+               ],
+               x: 0.03,
+               y: 0.05,
+       },
+       {
+               id: 'potion-shop',
+               checks: [
+                       'potion-shop',
+               ],
+               x: 0.8,
+               y: 0.325,
+       },
+       {
+               id: 'race-game',
+               checks: [
+                       'race-game',
+               ],
+               x: 0.025,
+               y: 0.7,
+       },
+       {
+               id: 'saha',
+               checks: [
+                       'saha',
+               ],
+               x: 0.815,
+               y: 0.465,
+       },
+       {
+               id: 'saha-hut',
+               checks: [
+                       'saha-left',
+                       'saha-mid',
+                       'saha-right',
+               ],
+               x: 0.815,
+               y: 0.42,
+       },
+       {
+               id: 'sick-kid',
+               checks: [
+                       'sick-kid',
+               ],
+               x: 0.155,
+               y: 0.525,
+       },
+       {
+               id: 'uncle',
+               checks: [
+                       'uncle',
+                       'secret-passage',
+               ],
+               x: 0.6,
+               y: 0.4,
+       },
+       {
+               id: 'spec-rock',
+               checks: [
+                       'spec-rock',
+               ],
+               x: 0.48,
+               y: 0.09,
+       },
+       {
+               id: 'spec-rock-cave',
+               checks: [
+                       'spec-rock-cave',
+               ],
+               x: 0.48,
+               y: 0.14,
+       },
+       {
+               id: 'spiral-cave',
+               checks: [
+                       'spiral-cave',
+               ],
+               x: 0.8,
+               y: 0.1,
+       },
+       {
+               id: 'tavern',
+               checks: [
+                       'tavern',
+               ],
+               x: 0.16,
+               y: 0.58,
+       },
+       {
+               id: 'waterfall-fairy',
+               checks: [
+                       'waterfall-fairy-left',
+                       'waterfall-fairy-right',
+               ],
+               x: 0.9,
+               y: 0.15,
+       },
+       {
+               id: 'zora',
+               checks: [
+                       'zora',
+               ],
+               x: 0.975,
+               y: 0.12,
+       },
+       {
+               id: 'zora-ledge',
+               checks: [
+                       'zora-ledge',
+               ],
+               x: 0.975,
+               y: 0.165,
+       },
+];
+
+const LW_LOCATIONS = [
+       ...GENERIC_LW_LOCATIONS,
+       {
+               id: 'links-house',
+               checks: [
+                       'links-house',
+               ],
+               x: 0.55,
+               y: 0.6875,
+       },
+];
+
+const INVERTED_LW_LOCATIONS = GENERIC_LW_LOCATIONS;
+
+const GENERIC_DW_DUNGEONS = [
+       {
+               id: 'pd',
+               x: 0.95,
+               y: 0.42,
+       },
+       {
+               id: 'sp',
+               x: 0.4675,
+               y: 0.9375,
+       },
+       {
+               id: 'sw',
+               x: 0.05,
+               y: 0.05,
+       },
+       {
+               id: 'tt',
+               x: 0.125,
+               y: 0.475,
+       },
+       {
+               id: 'ip',
+               x: 0.7975,
+               y: 0.86,
+       },
+       {
+               id: 'mm',
+               x: 0.12,
+               y: 0.82,
+       },
+       {
+               id: 'tr',
+               x: 0.94,
+               y: 0.06,
+       },
+];
+
+const DW_DUNGEONS = [
+       ...GENERIC_DW_DUNGEONS,
+       {
+               id: 'gt',
+               x: 0.56,
+               y: 0.05,
+       },
+];
+
+const INVERTED_DW_DUNGEONS = [
+       ...GENERIC_DW_DUNGEONS,
+       {
+               id: 'ct',
+               x: 0.56,
+               y: 0.05,
+       },
+];
+
+const GENERIC_DW_LOCATIONS = [
+       {
+               id: 'blacksmith',
+               checks: [
+                       'blacksmith',
+               ],
+               x: 0.15,
+               y: 0.65,
+       },
+       {
+               id: 'brewery',
+               checks: [
+                       'brewery',
+               ],
+               x: 0.1,
+               y: 0.6,
+       },
+       {
+               id: 'bumper-cave',
+               checks: [
+                       'bumper-cave',
+               ],
+               x: 0.325,
+               y: 0.15,
+       },
+       {
+               id: 'c-house',
+               checks: [
+                       'c-house',
+               ],
+               x: 0.2,
+               y: 0.5,
+       },
+       {
+               id: 'catfish',
+               checks: [
+                       'catfish',
+               ],
+               x: 0.9,
+               y: 0.175,
+       },
+       {
+               id: 'chest-game',
+               checks: [
+                       'chest-game',
+               ],
+               x: 0.05,
+               y: 0.45,
+       },
+       {
+               id: 'digging-game',
+               checks: [
+                       'digging-game',
+               ],
+               x: 0.05,
+               y: 0.7,
+       },
+       {
+               id: 'hammer-pegs',
+               checks: [
+                       'hammer-pegs',
+               ],
+               x: 0.3125,
+               y: 0.6,
+       },
+       {
+               id: 'hookshot-cave',
+               checks: [
+                       'hookshot-cave-tl',
+                       'hookshot-cave-tr',
+                       'hookshot-cave-bl',
+               ],
+               x: 0.85,
+               y: 0.02,
+       },
+       {
+               id: 'hookshot-cave-bonk',
+               checks: [
+                       'hookshot-cave-br',
+               ],
+               x: 0.85,
+               y: 0.065,
+       },
+       {
+               id: 'hype-cave',
+               checks: [
+                       'hype-cave-top',
+                       'hype-cave-left',
+                       'hype-cave-right',
+                       'hype-cave-bottom',
+                       'hype-cave-npc',
+               ],
+               x: 0.6,
+               y: 0.75,
+       },
+       {
+               id: 'mire-shed',
+               checks: [
+                       'mire-shed-left',
+                       'mire-shed-right',
+               ],
+               x: 0.04,
+               y: 0.8,
+       },
+       {
+               id: 'purple-chest',
+               checks: [
+                       'purple-chest',
+               ],
+               x: 0.3125,
+               y: 0.525,
+       },
+       {
+               id: 'pyramid',
+               checks: [
+                       'pyramid',
+               ],
+               x: 0.575,
+               y: 0.45,
+       },
+       {
+               id: 'pyramid-fairy',
+               checks: [
+                       'pyramid-fairy-left',
+                       'pyramid-fairy-right',
+               ],
+               x: 0.45,
+               y: 0.5,
+       },
+       {
+               id: 'spike-cave',
+               checks: [
+                       'spike-cave',
+               ],
+               x: 0.575,
+               y: 0.15,
+       },
+       {
+               id: 'stumpy',
+               checks: [
+                       'stumpy',
+               ],
+               x: 0.3125,
+               y: 0.6875,
+       },
+       {
+               id: 'super-bunny',
+               checks: [
+                       'super-bunny-top',
+                       'super-bunny-bottom',
+               ],
+               x: 0.85,
+               y: 0.15,
+       },
+];
+
+const DW_LOCATIONS = GENERIC_DW_LOCATIONS;
+
+const INVERTED_DW_LOCATIONS = [
+       ...GENERIC_DW_LOCATIONS,
+       {
+               id: 'links-house',
+               checks: [
+                       'links-house',
+               ],
+               x: 0.55,
+               y: 0.6875,
+       },
+];
+
+const Location = ({ number, l, size }) => {
+       const { t } = useTranslation();
+
+       const classNames = ['location', `status-${l.status}`];
+       if (size) {
+               classNames.push(`size-${size}`);
+       }
+       if (l.handlePrimary) {
+               classNames.push('clickable');
+       }
+
+       return <g
+               className={classNames.join(' ')}
+               onClick={(e) => {
+                       l.handlePrimary();
+                       e.preventDefault();
+                       e.stopPropagation();
+               }}
+               onContextMenu={(e) => {
+                       l.handleSecondary();
+                       e.preventDefault();
+                       e.stopPropagation();
+               }}
+               transform={`translate(${l.x} ${l.y})`}
+       >
+               <title>{t(`tracker.location.${l.id}`)}</title>
+               <rect className="box" x="0" y="0" />
+               {number && l.remaining ?
+                       <text className="text" x="0" y="0">{l.remaining}</text>
+               : null}
+       </g>;
+};
+
+Location.propTypes = {
+       number: PropTypes.bool,
+       l: PropTypes.shape({
+               id: PropTypes.string,
+               x: PropTypes.number,
+               y: PropTypes.number,
+               number: PropTypes.number,
+               remaining: PropTypes.number,
+               status: PropTypes.string,
+               handlePrimary: PropTypes.func,
+               handleSecondary: PropTypes.func,
+       }),
+       size: PropTypes.string,
+};
+
+const makeBackground = (src, level) => {
+       const amount = Math.pow(2, Math.max(0, level - 8));
+       const size = 1 / amount;
+       const tiles = [];
+       for (let y = 0; y < amount; ++y) {
+               for (let x = 0; x < amount; ++x) {
+                       tiles.push(<image
+                               key={`${x}-${y}`}
+                               x={x * size}
+                               y={y * size}
+                               width={size * 1.002}
+                               height={size * 1.002}
+                               href={`/media/alttp/map/${src}/${level}/${x}_${y}.png`}
+                       />);
+               }
+       }
+       return tiles;
+};
+
+const Overworld = () => {
+       const { config, dungeons, logic, setManualState, state } = useTracker();
+
+       const mapDungeon = React.useCallback(dungeon => {
+               const definition = dungeons.find(d => d.id === dungeon.id);
+               const remaining = getDungeonRemainingItems(state, definition);
+               const status = aggregateDungeonStatus(definition, logic, state);
+               return {
+                       ...dungeon,
+                       status,
+                       remaining,
+                       handlePrimary: () => {
+                               if (getDungeonRemainingItems(state, definition)) {
+                                       setManualState(addDungeonCheck(definition));
+                               } else if (
+                                       !hasDungeonBoss(state, definition) || !hasDungeonPrize(state, definition)
+                               ) {
+                                       if (definition.boss) {
+                                               setManualState(setBossDefeated(definition, true));
+                                       }
+                                       if (definition.prize) {
+                                               setManualState(setPrizeAcquired(definition, true));
+                                       }
+                               } else {
+                                       setManualState(resetDungeonChecks(definition));
+                                       if (definition.boss) {
+                                               setManualState(setBossDefeated(definition, false));
+                                       }
+                                       if (definition.prize) {
+                                               setManualState(setPrizeAcquired(definition, false));
+                                       }
+                               }
+                       },
+                       handleSecondary: () => {
+                               if (isDungeonCleared(state, definition)) {
+                                       if (definition.items) {
+                                               setManualState(removeDungeonCheck(definition));
+                                       }
+                                       if (definition.boss) {
+                                               setManualState(setBossDefeated(definition, false));
+                                       }
+                                       if (definition.prize) {
+                                               setManualState(setPrizeAcquired(definition, false));
+                                       }
+                               } else if (getDungeonClearedItems(state, definition)) {
+                                       setManualState(removeDungeonCheck(definition));
+                               } else {
+                                       setManualState(completeDungeonChecks(definition));
+                                       if (definition.boss) {
+                                               setManualState(setBossDefeated(definition, true));
+                                       }
+                                       if (definition.prize) {
+                                               setManualState(setPrizeAcquired(definition, true));
+                                       }
+                               }
+                       },
+               };
+       }, [dungeons, logic, setManualState, state]);
+
+       const mapLocation = React.useCallback(loc => {
+               const remaining = countRemainingLocations(state, loc.checks);
+               const status = aggregateLocationStatus(loc.checks, logic, state);
+               return {
+                       ...loc,
+                       remaining,
+                       status,
+                       handlePrimary: () => {
+                               if (remaining) {
+                                       setManualState(clearAll(loc.checks));
+                               } else {
+                                       setManualState(unclearAll(loc.checks));
+                               }
+                       },
+                       handleSecondary: () => {
+                               if (remaining) {
+                                       setManualState(clearAll(loc.checks));
+                               } else {
+                                       setManualState(unclearAll(loc.checks));
+                               }
+                       },
+               };
+       }, [logic, setManualState, state]);
+
+       const lwDungeons = React.useMemo(() =>
+               (config.worldState === 'inverted' ? INVERTED_LW_DUNGEONS : LW_DUNGEONS)
+               .map(mapDungeon)
+       , [mapDungeon]);
+       const lwLocations = React.useMemo(() =>
+               (config.worldState === 'inverted' ? INVERTED_LW_LOCATIONS : LW_LOCATIONS)
+               .map(mapLocation)
+       , [mapLocation]);
+
+       const dwDungeons = React.useMemo(() =>
+               (config.worldState === 'inverted' ? INVERTED_DW_DUNGEONS : DW_DUNGEONS)
+               .map(mapDungeon)
+       , [mapDungeon]);
+       const dwLocations = React.useMemo(() =>
+               (config.worldState === 'inverted' ? INVERTED_DW_LOCATIONS : DW_LOCATIONS)
+               .map(mapLocation)
+       , [mapLocation]);
+
+       const layout = React.useMemo(() => {
+               if (config.mapLayout === 'vertical') {
+                       return {
+                               lwTransform: '',
+                               dwTransform: 'translate(0 1)',
+                       };
+               } else {
+                       return {
+                               lwTransform: 'scale(0.5)',
+                               dwTransform: 'scale(0.5) translate(1 0)',
+                       };
+               }
+       }, [config]);
+
+       return <>
+               <g className="light-world" transform={layout.lwTransform}>
+                       <g className="background">
+                               {makeBackground('lw_files', 10)}
+                       </g>
+                       <g className="locations">
+                               {lwLocations.map(l =>
+                                       <Location key={l.id} l={l} />
+                               )}
+                               {lwDungeons.map(l =>
+                                       <Location key={l.id} number l={l} size="lg" />
+                               )}
+                       </g>
+               </g>
+               <g className="dark-world" transform={layout.dwTransform}>
+                       <g className="background">
+                               {makeBackground('dw_files', 10)}
+                       </g>
+                       <g className="locations">
+                               {dwLocations.map(l =>
+                                       <Location key={l.id} l={l} />
+                               )}
+                               {dwDungeons.map(l =>
+                                       <Location key={l.id} number l={l} size="lg" />
+                               )}
+                       </g>
+               </g>
+       </>;
+};
+
+export default Overworld;
diff --git a/resources/js/components/tracker/Map/index.js b/resources/js/components/tracker/Map/index.js
deleted file mode 100644 (file)
index 246403c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-
-import Overworld from './Overworld';
-
-const Map = () => {
-       return <>
-               <Overworld />
-       </>;
-};
-
-export default Map;
diff --git a/resources/js/components/tracker/Map/index.jsx b/resources/js/components/tracker/Map/index.jsx
new file mode 100644 (file)
index 0000000..246403c
--- /dev/null
@@ -0,0 +1,11 @@
+import React from 'react';
+
+import Overworld from './Overworld';
+
+const Map = () => {
+       return <>
+               <Overworld />
+       </>;
+};
+
+export default Map;
diff --git a/resources/js/components/tracker/ToggleIcon.js b/resources/js/components/tracker/ToggleIcon.js
deleted file mode 100644 (file)
index d3e3960..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import ZeldaIcon from '../common/ZeldaIcon';
-import {
-       addDungeonCheck,
-       decrement,
-       getDungeonBoss,
-       getDungeonRemainingItems,
-       getDungeonPrize,
-       getGTBoss,
-       hasDungeonBoss,
-       hasDungeonPrize,
-       highestActive,
-       increment,
-       removeDungeonCheck,
-       toggleBoolean,
-       toggleBossDefeated,
-} from '../../helpers/tracker';
-import { useTracker } from '../../hooks/tracker';
-
-const ToggleIcon = ({ controller, className, icons, svg, title, transform }) => {
-       const { setManualState, state } = useTracker();
-       const activeController = controller || ToggleIcon.nullController;
-       const active = activeController.getActive(state, icons);
-       const defaultIcon = activeController.getDefault(state, icons);
-       const icon = active || defaultIcon || icons[0];
-       const classNames = ['toggle-icon'];
-       if (active) {
-               classNames.push('active');
-       } else {
-               classNames.push('inactive');
-       }
-       if (className) {
-               classNames.push(className);
-       }
-       if (svg) {
-               return <g
-                       className={classNames.join(' ')}
-                       data-icon={icon}
-                       onClick={(e) => {
-                               activeController.handlePrimary(state, setManualState, icons);
-                               e.preventDefault();
-                               e.stopPropagation();
-                       }}
-                       onContextMenu={(e) => {
-                               activeController.handleSecondary(state, setManualState, icons);
-                               e.preventDefault();
-                               e.stopPropagation();
-                       }}
-                       transform={transform}
-               >
-                       <ZeldaIcon name={icon} svg title={title} />
-               </g>;
-       }
-       return <span
-               className={classNames.join(' ')}
-               onClick={(e) => {
-                       activeController.handlePrimary(state, setManualState, icons);
-                       e.preventDefault();
-                       e.stopPropagation();
-               }}
-               onContextMenu={(e) => {
-                       activeController.handleSecondary(state, setManualState, icons);
-                       e.preventDefault();
-                       e.stopPropagation();
-               }}
-       >
-               <ZeldaIcon name={active || defaultIcon || icons[0]} title={title} />
-       </span>;
-};
-
-const doNothing = () => { };
-
-const firstIcon = (state, icons) => icons[0];
-
-const nextIcon = (state, setState, icons) => {
-       const highest = highestActive(state, icons);
-       const highestIndex = highest ? icons.indexOf(highest) : -1;
-       if (highestIndex + 1 < icons.length) {
-               setState(toggleBoolean(icons[highestIndex + 1]));
-       } else {
-               const changes = {};
-               icons.forEach(icon => {
-                       changes[icon] = false;
-               });
-               setState(s => ({ ...s, ...changes }));
-       }
-};
-
-const previousIcon = (state, setState, icons) => {
-       const highest = highestActive(state, icons);
-       const highestIndex = highest ? icons.indexOf(highest) : -1;
-       if (highestIndex >= 0) {
-               setState(toggleBoolean(icons[highestIndex]));
-       } else {
-               const changes = {};
-               icons.forEach(icon => {
-                       changes[icon] = true;
-               });
-               setState(s => ({ ...s, ...changes }));
-       }
-};
-
-const nextString = property => (state, setState, icons) => {
-       const current = state[property] || icons[0];
-       const currentIndex = icons.indexOf(current);
-       const nextIndex = (currentIndex + 1) % icons.length;
-       const next = icons[nextIndex];
-       setState(s => ({ ...s, [property]: next }));
-};
-
-const previousString = property => (state, setState, icons) => {
-       const current = state[property] || icons[0];
-       const currentIndex = icons.indexOf(current);
-       const previousIndex = (currentIndex + icons.length - 1) % icons.length;
-       const previous = icons[previousIndex];
-       setState(s => ({ ...s, [property]: previous }));
-};
-
-ToggleIcon.bottleController = ctrl => ({
-       getActive: (state, icons) => state[ctrl] ? icons[state[ctrl] - 1] : null,
-       getDefault: () => 'bottle',
-       handlePrimary: (state, setState, icons) => {
-               if (state[ctrl] === 0) {
-                       // skip over mushroom
-                       setState(s => ({ ...s, [ctrl]: 2 }));
-               } else {
-                       setState(increment(ctrl, icons.length));
-               }
-       },
-       handleSecondary: (state, setState, icons) => {
-               if (state[ctrl] === 2) {
-                       // skip over mushroom
-                       setState(s => ({ ...s, [ctrl]: 0 }));
-               } else {
-                       setState(decrement(ctrl, icons.length));
-               }
-       },
-});
-
-ToggleIcon.countController = max => ({
-       getActive: highestActive,
-       getDefault: firstIcon,
-       handlePrimary: (state, setState, icons) => {
-               setState(increment(icons[0], max));
-       },
-       handleSecondary: (state, setState, icons) => {
-               setState(decrement(icons[0], max));
-       },
-});
-
-ToggleIcon.dungeonBossController = (dungeon) => ({
-       getActive: (state) => hasDungeonBoss(state, dungeon) ? getDungeonBoss(state, dungeon) : null,
-       getDefault: (state) => getDungeonBoss(state, dungeon),
-       handlePrimary: dungeon.bosses.length > 1
-               ? nextString(`${dungeon.id}-boss`)
-               : (state, setState) => {
-                       setState(toggleBossDefeated(dungeon));
-               },
-       handleSecondary: dungeon.bosses.length > 1 ?
-               previousString(`${dungeon.id}-boss`)
-               : (state, setState) => {
-                       setState(toggleBossDefeated(dungeon));
-               },
-});
-
-ToggleIcon.dungeonCheckController = (dungeon) => ({
-       getActive: (state, icons) => getDungeonRemainingItems(state, dungeon) ? icons[1] : null,
-       getDefault: firstIcon,
-       handlePrimary: (state, setState) => {
-               setState(addDungeonCheck(dungeon));
-       },
-       handleSecondary: (state, setState) => {
-               setState(removeDungeonCheck(dungeon));
-       },
-});
-
-ToggleIcon.dungeonController = dungeon => ({
-       getActive: (state, icons) => state[`${dungeon.id}-${icons[0]}`] ? icons[0] : null,
-       getDefault: firstIcon,
-       handlePrimary: (state, setState, icons) => {
-               setState(toggleBoolean(`${dungeon.id}-${icons[0]}`));
-       },
-       handleSecondary: (state, setState, icons) => {
-               setState(toggleBoolean(`${dungeon.id}-${icons[0]}`));
-       },
-});
-
-ToggleIcon.dungeonCountController = (dungeon, max) => ({
-       getActive: (state, icons) => state[`${dungeon.id}-${icons[0]}`] ? icons[0] : null,
-       getDefault: firstIcon,
-       handlePrimary: (state, setState, icons) => {
-               setState(increment(`${dungeon.id}-${icons[0]}`, max));
-       },
-       handleSecondary: (state, setState, icons) => {
-               setState(decrement(`${dungeon.id}-${icons[0]}`, max));
-       },
-});
-
-ToggleIcon.dungeonPrizeController = (dungeon) => ({
-       getActive: (state) => hasDungeonPrize(state, dungeon) ? getDungeonPrize(state, dungeon) : null,
-       getDefault: (state) => getDungeonPrize(state, dungeon),
-       handlePrimary: nextString(`${dungeon.id}-prize`),
-       handleSecondary: previousString(`${dungeon.id}-prize`),
-});
-
-ToggleIcon.gtBossController = (which) => ({
-       getActive: (state) => getGTBoss(state, which),
-       getDefault: (state) => getGTBoss(state, which),
-       handlePrimary: nextString(`gt-${which}-boss`),
-       handleSecondary: previousString(`gt-${which}-boss`),
-});
-
-ToggleIcon.medallionController = {
-       getActive: highestActive,
-       getDefault: firstIcon,
-       handlePrimary: nextIcon,
-       handleSecondary: (state, setState, icons) => {
-               const mm = state['mm-medallion'];
-               const tr = state['tr-medallion'];
-               const isMM = mm === icons[0];
-               const isTR = tr === icons[0];
-               console.log({ mm, isMM, tr, isTR });
-               if (!isMM && !isTR) {
-                       // empty: set as MM if mire is unset, else set as TR if TR is unset
-                       if (!mm) {
-                               setState(s => ({ ...s, 'mm-medallion': icons[0] }));
-                       } else if (!tr) {
-                               setState(s => ({ ...s, 'tr-medallion': icons[0] }));
-                       }
-               } else if (isMM && !isTR) {
-                       // MM: if TR is free, switch to TR, otherwise remove MM
-                       if (!tr) {
-                               setState(s => ({ ...s, 'mm-medallion': null, 'tr-medallion': icons[0] }));
-                       } else {
-                               setState(s => ({ ...s, 'mm-medallion': null }));
-                       }
-               } else if (!isMM && isTR) {
-                       // TR: if MM is free, switch to both, otherwise remove TR
-                       if (!mm) {
-                               setState(s => ({ ...s, 'mm-medallion': icons[0] }));
-                       } else {
-                               setState(s => ({ ...s, 'tr-medallion': null }));
-                       }
-               } else {
-                       // both: remove both
-                       setState(s => ({ ...s, 'mm-medallion': null, 'tr-medallion': null }));
-               }
-       },
-};
-
-ToggleIcon.modulusController = ctrl => ({
-       getActive: (state, icons) => icons[(state[ctrl] || 0) % icons.length],
-       getDefault: firstIcon,
-       handlePrimary: (state, setState, icons) => {
-               setState(increment(ctrl, icons.length));
-       },
-       handleSecondary: (state, setState, icons) => {
-               setState(decrement(ctrl, icons.length));
-       },
-});
-
-ToggleIcon.nullController = {
-       getActive: () => null,
-       getDefault: firstIcon,
-       handlePrimary: doNothing,
-       handleSecondary: doNothing,
-};
-
-ToggleIcon.pinController = (pin, removePin) => ({
-       getActive: firstIcon,
-       getDefault: firstIcon,
-       handlePrimary: doNothing,
-       handleSecondary: () => removePin(pin),
-});
-
-ToggleIcon.simpleController = {
-       getActive: highestActive,
-       getDefault: firstIcon,
-       handlePrimary: nextIcon,
-       handleSecondary: previousIcon,
-};
-
-ToggleIcon.progressiveController = (master, min, max) => ({
-       getActive: (state, icons) => {
-               const count = Math.max(min, Math.min(max, state[master] || 0));
-               return count ? icons[count - 1] : null;
-       },
-       getDefault: firstIcon,
-       handlePrimary: (state, setState) => {
-               setState(increment(master, max, min));
-       },
-       handleSecondary: (state, setState) => {
-               setState(decrement(master, max, min));
-       },
-});
-
-ToggleIcon.propTypes = {
-       active: PropTypes.string,
-       className: PropTypes.string,
-       controller: PropTypes.shape({
-               handlePrimary: PropTypes.func,
-               handleSecondary: PropTypes.func,
-       }),
-       icons: PropTypes.arrayOf(PropTypes.string),
-       svg: PropTypes.bool,
-       title: PropTypes.string,
-       transform: PropTypes.string,
-};
-
-export default ToggleIcon;
diff --git a/resources/js/components/tracker/ToggleIcon.jsx b/resources/js/components/tracker/ToggleIcon.jsx
new file mode 100644 (file)
index 0000000..d3e3960
--- /dev/null
@@ -0,0 +1,312 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import ZeldaIcon from '../common/ZeldaIcon';
+import {
+       addDungeonCheck,
+       decrement,
+       getDungeonBoss,
+       getDungeonRemainingItems,
+       getDungeonPrize,
+       getGTBoss,
+       hasDungeonBoss,
+       hasDungeonPrize,
+       highestActive,
+       increment,
+       removeDungeonCheck,
+       toggleBoolean,
+       toggleBossDefeated,
+} from '../../helpers/tracker';
+import { useTracker } from '../../hooks/tracker';
+
+const ToggleIcon = ({ controller, className, icons, svg, title, transform }) => {
+       const { setManualState, state } = useTracker();
+       const activeController = controller || ToggleIcon.nullController;
+       const active = activeController.getActive(state, icons);
+       const defaultIcon = activeController.getDefault(state, icons);
+       const icon = active || defaultIcon || icons[0];
+       const classNames = ['toggle-icon'];
+       if (active) {
+               classNames.push('active');
+       } else {
+               classNames.push('inactive');
+       }
+       if (className) {
+               classNames.push(className);
+       }
+       if (svg) {
+               return <g
+                       className={classNames.join(' ')}
+                       data-icon={icon}
+                       onClick={(e) => {
+                               activeController.handlePrimary(state, setManualState, icons);
+                               e.preventDefault();
+                               e.stopPropagation();
+                       }}
+                       onContextMenu={(e) => {
+                               activeController.handleSecondary(state, setManualState, icons);
+                               e.preventDefault();
+                               e.stopPropagation();
+                       }}
+                       transform={transform}
+               >
+                       <ZeldaIcon name={icon} svg title={title} />
+               </g>;
+       }
+       return <span
+               className={classNames.join(' ')}
+               onClick={(e) => {
+                       activeController.handlePrimary(state, setManualState, icons);
+                       e.preventDefault();
+                       e.stopPropagation();
+               }}
+               onContextMenu={(e) => {
+                       activeController.handleSecondary(state, setManualState, icons);
+                       e.preventDefault();
+                       e.stopPropagation();
+               }}
+       >
+               <ZeldaIcon name={active || defaultIcon || icons[0]} title={title} />
+       </span>;
+};
+
+const doNothing = () => { };
+
+const firstIcon = (state, icons) => icons[0];
+
+const nextIcon = (state, setState, icons) => {
+       const highest = highestActive(state, icons);
+       const highestIndex = highest ? icons.indexOf(highest) : -1;
+       if (highestIndex + 1 < icons.length) {
+               setState(toggleBoolean(icons[highestIndex + 1]));
+       } else {
+               const changes = {};
+               icons.forEach(icon => {
+                       changes[icon] = false;
+               });
+               setState(s => ({ ...s, ...changes }));
+       }
+};
+
+const previousIcon = (state, setState, icons) => {
+       const highest = highestActive(state, icons);
+       const highestIndex = highest ? icons.indexOf(highest) : -1;
+       if (highestIndex >= 0) {
+               setState(toggleBoolean(icons[highestIndex]));
+       } else {
+               const changes = {};
+               icons.forEach(icon => {
+                       changes[icon] = true;
+               });
+               setState(s => ({ ...s, ...changes }));
+       }
+};
+
+const nextString = property => (state, setState, icons) => {
+       const current = state[property] || icons[0];
+       const currentIndex = icons.indexOf(current);
+       const nextIndex = (currentIndex + 1) % icons.length;
+       const next = icons[nextIndex];
+       setState(s => ({ ...s, [property]: next }));
+};
+
+const previousString = property => (state, setState, icons) => {
+       const current = state[property] || icons[0];
+       const currentIndex = icons.indexOf(current);
+       const previousIndex = (currentIndex + icons.length - 1) % icons.length;
+       const previous = icons[previousIndex];
+       setState(s => ({ ...s, [property]: previous }));
+};
+
+ToggleIcon.bottleController = ctrl => ({
+       getActive: (state, icons) => state[ctrl] ? icons[state[ctrl] - 1] : null,
+       getDefault: () => 'bottle',
+       handlePrimary: (state, setState, icons) => {
+               if (state[ctrl] === 0) {
+                       // skip over mushroom
+                       setState(s => ({ ...s, [ctrl]: 2 }));
+               } else {
+                       setState(increment(ctrl, icons.length));
+               }
+       },
+       handleSecondary: (state, setState, icons) => {
+               if (state[ctrl] === 2) {
+                       // skip over mushroom
+                       setState(s => ({ ...s, [ctrl]: 0 }));
+               } else {
+                       setState(decrement(ctrl, icons.length));
+               }
+       },
+});
+
+ToggleIcon.countController = max => ({
+       getActive: highestActive,
+       getDefault: firstIcon,
+       handlePrimary: (state, setState, icons) => {
+               setState(increment(icons[0], max));
+       },
+       handleSecondary: (state, setState, icons) => {
+               setState(decrement(icons[0], max));
+       },
+});
+
+ToggleIcon.dungeonBossController = (dungeon) => ({
+       getActive: (state) => hasDungeonBoss(state, dungeon) ? getDungeonBoss(state, dungeon) : null,
+       getDefault: (state) => getDungeonBoss(state, dungeon),
+       handlePrimary: dungeon.bosses.length > 1
+               ? nextString(`${dungeon.id}-boss`)
+               : (state, setState) => {
+                       setState(toggleBossDefeated(dungeon));
+               },
+       handleSecondary: dungeon.bosses.length > 1 ?
+               previousString(`${dungeon.id}-boss`)
+               : (state, setState) => {
+                       setState(toggleBossDefeated(dungeon));
+               },
+});
+
+ToggleIcon.dungeonCheckController = (dungeon) => ({
+       getActive: (state, icons) => getDungeonRemainingItems(state, dungeon) ? icons[1] : null,
+       getDefault: firstIcon,
+       handlePrimary: (state, setState) => {
+               setState(addDungeonCheck(dungeon));
+       },
+       handleSecondary: (state, setState) => {
+               setState(removeDungeonCheck(dungeon));
+       },
+});
+
+ToggleIcon.dungeonController = dungeon => ({
+       getActive: (state, icons) => state[`${dungeon.id}-${icons[0]}`] ? icons[0] : null,
+       getDefault: firstIcon,
+       handlePrimary: (state, setState, icons) => {
+               setState(toggleBoolean(`${dungeon.id}-${icons[0]}`));
+       },
+       handleSecondary: (state, setState, icons) => {
+               setState(toggleBoolean(`${dungeon.id}-${icons[0]}`));
+       },
+});
+
+ToggleIcon.dungeonCountController = (dungeon, max) => ({
+       getActive: (state, icons) => state[`${dungeon.id}-${icons[0]}`] ? icons[0] : null,
+       getDefault: firstIcon,
+       handlePrimary: (state, setState, icons) => {
+               setState(increment(`${dungeon.id}-${icons[0]}`, max));
+       },
+       handleSecondary: (state, setState, icons) => {
+               setState(decrement(`${dungeon.id}-${icons[0]}`, max));
+       },
+});
+
+ToggleIcon.dungeonPrizeController = (dungeon) => ({
+       getActive: (state) => hasDungeonPrize(state, dungeon) ? getDungeonPrize(state, dungeon) : null,
+       getDefault: (state) => getDungeonPrize(state, dungeon),
+       handlePrimary: nextString(`${dungeon.id}-prize`),
+       handleSecondary: previousString(`${dungeon.id}-prize`),
+});
+
+ToggleIcon.gtBossController = (which) => ({
+       getActive: (state) => getGTBoss(state, which),
+       getDefault: (state) => getGTBoss(state, which),
+       handlePrimary: nextString(`gt-${which}-boss`),
+       handleSecondary: previousString(`gt-${which}-boss`),
+});
+
+ToggleIcon.medallionController = {
+       getActive: highestActive,
+       getDefault: firstIcon,
+       handlePrimary: nextIcon,
+       handleSecondary: (state, setState, icons) => {
+               const mm = state['mm-medallion'];
+               const tr = state['tr-medallion'];
+               const isMM = mm === icons[0];
+               const isTR = tr === icons[0];
+               console.log({ mm, isMM, tr, isTR });
+               if (!isMM && !isTR) {
+                       // empty: set as MM if mire is unset, else set as TR if TR is unset
+                       if (!mm) {
+                               setState(s => ({ ...s, 'mm-medallion': icons[0] }));
+                       } else if (!tr) {
+                               setState(s => ({ ...s, 'tr-medallion': icons[0] }));
+                       }
+               } else if (isMM && !isTR) {
+                       // MM: if TR is free, switch to TR, otherwise remove MM
+                       if (!tr) {
+                               setState(s => ({ ...s, 'mm-medallion': null, 'tr-medallion': icons[0] }));
+                       } else {
+                               setState(s => ({ ...s, 'mm-medallion': null }));
+                       }
+               } else if (!isMM && isTR) {
+                       // TR: if MM is free, switch to both, otherwise remove TR
+                       if (!mm) {
+                               setState(s => ({ ...s, 'mm-medallion': icons[0] }));
+                       } else {
+                               setState(s => ({ ...s, 'tr-medallion': null }));
+                       }
+               } else {
+                       // both: remove both
+                       setState(s => ({ ...s, 'mm-medallion': null, 'tr-medallion': null }));
+               }
+       },
+};
+
+ToggleIcon.modulusController = ctrl => ({
+       getActive: (state, icons) => icons[(state[ctrl] || 0) % icons.length],
+       getDefault: firstIcon,
+       handlePrimary: (state, setState, icons) => {
+               setState(increment(ctrl, icons.length));
+       },
+       handleSecondary: (state, setState, icons) => {
+               setState(decrement(ctrl, icons.length));
+       },
+});
+
+ToggleIcon.nullController = {
+       getActive: () => null,
+       getDefault: firstIcon,
+       handlePrimary: doNothing,
+       handleSecondary: doNothing,
+};
+
+ToggleIcon.pinController = (pin, removePin) => ({
+       getActive: firstIcon,
+       getDefault: firstIcon,
+       handlePrimary: doNothing,
+       handleSecondary: () => removePin(pin),
+});
+
+ToggleIcon.simpleController = {
+       getActive: highestActive,
+       getDefault: firstIcon,
+       handlePrimary: nextIcon,
+       handleSecondary: previousIcon,
+};
+
+ToggleIcon.progressiveController = (master, min, max) => ({
+       getActive: (state, icons) => {
+               const count = Math.max(min, Math.min(max, state[master] || 0));
+               return count ? icons[count - 1] : null;
+       },
+       getDefault: firstIcon,
+       handlePrimary: (state, setState) => {
+               setState(increment(master, max, min));
+       },
+       handleSecondary: (state, setState) => {
+               setState(decrement(master, max, min));
+       },
+});
+
+ToggleIcon.propTypes = {
+       active: PropTypes.string,
+       className: PropTypes.string,
+       controller: PropTypes.shape({
+               handlePrimary: PropTypes.func,
+               handleSecondary: PropTypes.func,
+       }),
+       icons: PropTypes.arrayOf(PropTypes.string),
+       svg: PropTypes.bool,
+       title: PropTypes.string,
+       transform: PropTypes.string,
+};
+
+export default ToggleIcon;
diff --git a/resources/js/components/tracker/Toolbar.js b/resources/js/components/tracker/Toolbar.js
deleted file mode 100644 (file)
index f9d488a..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-import React from 'react';
-import { Button, Container, Form, Navbar } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import AutoTracking from './AutoTracking';
-import ConfigDialog from './ConfigDialog';
-import ToggleIcon from './ToggleIcon';
-import Icon from '../common/Icon';
-import ZeldaIcon from '../common/ZeldaIcon';
-import { getConfigValue } from '../../helpers/tracker';
-import { useTracker } from '../../hooks/tracker';
-
-const mapWild = {
-       map: 'wildMap',
-       compass: 'wildCompass',
-       'small-key': 'wildSmall',
-       'big-key': 'wildBig',
-};
-
-const Toolbar = () => {
-       const [showConfigDialog, setShowConfigDialog] = React.useState(false);
-       const { config, saveConfig } = useTracker();
-       const { t } = useTranslation();
-
-       const handleConfigChange = React.useCallback(({ target: { name, value } }) => {
-               saveConfig({ [name]: value });
-       }, [saveConfig]);
-
-       const bossController = React.useMemo(() => ({
-               getActive: (state, icons) => config.bossShuffle ? icons[0] : null,
-               getDefault: (state, icons) => icons[0],
-               handlePrimary: () => {
-                       saveConfig({ bossShuffle: !config.bossShuffle});
-               },
-               handleSecondary: () => null,
-       }), [config, saveConfig]);
-
-       const wildController = React.useMemo(() => ({
-               getActive: (state, icons) => config[mapWild[icons[0]]] ? icons[0] : null,
-               getDefault: (state, icons) => icons[0],
-               handlePrimary: (state, setState, icons) => {
-                       const prop = mapWild[icons[0]];
-                       saveConfig({ [prop]: !config[prop] });
-               },
-               handleSecondary: () => null,
-       }), [config, saveConfig]);
-
-       const worldController = React.useMemo(() => ({
-               getActive: (state, icons) => config.worldState === 'inverted' ? icons[1] : icons[0],
-               getDefault: (state, icons) => icons[0],
-               handlePrimary: () => {
-                       saveConfig({ worldState: config.worldState == 'inverted' ? 'open' : 'inverted' });
-               },
-               handleSecondary: () => null,
-       }), [config, saveConfig]);
-
-       return <Navbar bg="dark" className="tracker-toolbar" variant="dark">
-               <Container fluid>
-                       <div className="button-bar">
-                               <Button
-                                       className="me-3"
-                                       onClick={() => setShowConfigDialog(true)}
-                                       title={t('button.settings')}
-                                       variant="outline-secondary"
-                               >
-                                       <Icon.SETTINGS title="" />
-                               </Button>
-                               <ToggleIcon
-                                       controller={wildController}
-                                       icons={['map']}
-                                       title={t('tracker.config.shuffleMap')}
-                               />
-                               <ToggleIcon
-                                       controller={wildController}
-                                       icons={['compass']}
-                                       title={t('tracker.config.shuffleCompass')}
-                               />
-                               <ToggleIcon
-                                       controller={wildController}
-                                       icons={['small-key']}
-                                       title={t('tracker.config.shuffleSmall')}
-                               />
-                               <ToggleIcon
-                                       controller={wildController}
-                                       icons={['big-key']}
-                                       title={t('tracker.config.shuffleBig')}
-                               />
-                               <ToggleIcon
-                                       className="ms-3"
-                                       controller={bossController}
-                                       icons={['armos']}
-                                       title={t('tracker.config.bossShuffle')}
-                               />
-                               <ToggleIcon
-                                       controller={worldController}
-                                       icons={['link-head', 'bunny-head']}
-                                       title={t('tracker.config.inverted')}
-                               />
-                       </div>
-                       <div>
-                               <Form.Group
-                                       className="d-inline-flex align-items-center justify-content-between"
-                                       controlId="tracker.gtCrystals"
-                               >
-                                       <Form.Label className="me-1">
-                                               <ZeldaIcon name="gt" title={t('tracker.config.gtCrystals')} />
-                                       </Form.Label>
-                                       <Form.Select
-                                               className="w-auto bg-dark"
-                                               name="gt-crystals"
-                                               onChange={handleConfigChange}
-                                               value={getConfigValue(config, 'gt-crystals', 7)}
-                                       >
-                                               {['?', 0, 1, 2, 3, 4, 5, 6, 7].map(n =>
-                                                       <option key={n} value={n}>
-                                                               {n}
-                                                       </option>
-                                               )}
-                                       </Form.Select>
-                               </Form.Group>
-                               <Form.Group
-                                       className="d-inline-flex align-items-center justify-content-between"
-                                       controlId="tracker.ganonCrystals"
-                               >
-                                       <Form.Label className="me-1">
-                                               <ZeldaIcon name="ganon" title={t('tracker.config.ganonCrystals')} />
-                                       </Form.Label>
-                                       <Form.Select
-                                               className="w-auto bg-dark"
-                                               name="ganon-crystals"
-                                               onChange={handleConfigChange}
-                                               value={getConfigValue(config, 'ganon-crystals', 7)}
-                                       >
-                                               {['?', 0, 1, 2, 3, 4, 5, 6, 7].map(n =>
-                                                       <option key={n} value={n}>
-                                                               {n}
-                                                       </option>
-                                               )}
-                                       </Form.Select>
-                               </Form.Group>
-                               <Form.Group
-                                       className="d-inline-flex align-items-center justify-content-between"
-                                       controlId="tracker.goal"
-                               >
-                                       <Form.Label className="me-1">
-                                               <ZeldaIcon name="triforce" title={t('tracker.config.goal')} />
-                                       </Form.Label>
-                                       <Form.Select
-                                               className="w-auto bg-dark"
-                                               name="goal"
-                                               onChange={handleConfigChange}
-                                               value={getConfigValue(config, 'goal', 'ganon')}
-                                       >
-                                               {['ganon', 'fast', 'ad', 'ped', 'trinity', 'thunt', 'ghunt'].map(n =>
-                                                       <option key={n} value={n}>
-                                                               {t(`tracker.config.goals.${n}`)}
-                                                       </option>
-                                               )}
-                                       </Form.Select>
-                               </Form.Group>
-                       </div>
-                       <div>
-                               <AutoTracking />
-                       </div>
-               </Container>
-               <ConfigDialog onHide={() => setShowConfigDialog(false)} show={showConfigDialog} />
-       </Navbar>;
-};
-
-export default Toolbar;
diff --git a/resources/js/components/tracker/Toolbar.jsx b/resources/js/components/tracker/Toolbar.jsx
new file mode 100644 (file)
index 0000000..f9d488a
--- /dev/null
@@ -0,0 +1,170 @@
+import React from 'react';
+import { Button, Container, Form, Navbar } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import AutoTracking from './AutoTracking';
+import ConfigDialog from './ConfigDialog';
+import ToggleIcon from './ToggleIcon';
+import Icon from '../common/Icon';
+import ZeldaIcon from '../common/ZeldaIcon';
+import { getConfigValue } from '../../helpers/tracker';
+import { useTracker } from '../../hooks/tracker';
+
+const mapWild = {
+       map: 'wildMap',
+       compass: 'wildCompass',
+       'small-key': 'wildSmall',
+       'big-key': 'wildBig',
+};
+
+const Toolbar = () => {
+       const [showConfigDialog, setShowConfigDialog] = React.useState(false);
+       const { config, saveConfig } = useTracker();
+       const { t } = useTranslation();
+
+       const handleConfigChange = React.useCallback(({ target: { name, value } }) => {
+               saveConfig({ [name]: value });
+       }, [saveConfig]);
+
+       const bossController = React.useMemo(() => ({
+               getActive: (state, icons) => config.bossShuffle ? icons[0] : null,
+               getDefault: (state, icons) => icons[0],
+               handlePrimary: () => {
+                       saveConfig({ bossShuffle: !config.bossShuffle});
+               },
+               handleSecondary: () => null,
+       }), [config, saveConfig]);
+
+       const wildController = React.useMemo(() => ({
+               getActive: (state, icons) => config[mapWild[icons[0]]] ? icons[0] : null,
+               getDefault: (state, icons) => icons[0],
+               handlePrimary: (state, setState, icons) => {
+                       const prop = mapWild[icons[0]];
+                       saveConfig({ [prop]: !config[prop] });
+               },
+               handleSecondary: () => null,
+       }), [config, saveConfig]);
+
+       const worldController = React.useMemo(() => ({
+               getActive: (state, icons) => config.worldState === 'inverted' ? icons[1] : icons[0],
+               getDefault: (state, icons) => icons[0],
+               handlePrimary: () => {
+                       saveConfig({ worldState: config.worldState == 'inverted' ? 'open' : 'inverted' });
+               },
+               handleSecondary: () => null,
+       }), [config, saveConfig]);
+
+       return <Navbar bg="dark" className="tracker-toolbar" variant="dark">
+               <Container fluid>
+                       <div className="button-bar">
+                               <Button
+                                       className="me-3"
+                                       onClick={() => setShowConfigDialog(true)}
+                                       title={t('button.settings')}
+                                       variant="outline-secondary"
+                               >
+                                       <Icon.SETTINGS title="" />
+                               </Button>
+                               <ToggleIcon
+                                       controller={wildController}
+                                       icons={['map']}
+                                       title={t('tracker.config.shuffleMap')}
+                               />
+                               <ToggleIcon
+                                       controller={wildController}
+                                       icons={['compass']}
+                                       title={t('tracker.config.shuffleCompass')}
+                               />
+                               <ToggleIcon
+                                       controller={wildController}
+                                       icons={['small-key']}
+                                       title={t('tracker.config.shuffleSmall')}
+                               />
+                               <ToggleIcon
+                                       controller={wildController}
+                                       icons={['big-key']}
+                                       title={t('tracker.config.shuffleBig')}
+                               />
+                               <ToggleIcon
+                                       className="ms-3"
+                                       controller={bossController}
+                                       icons={['armos']}
+                                       title={t('tracker.config.bossShuffle')}
+                               />
+                               <ToggleIcon
+                                       controller={worldController}
+                                       icons={['link-head', 'bunny-head']}
+                                       title={t('tracker.config.inverted')}
+                               />
+                       </div>
+                       <div>
+                               <Form.Group
+                                       className="d-inline-flex align-items-center justify-content-between"
+                                       controlId="tracker.gtCrystals"
+                               >
+                                       <Form.Label className="me-1">
+                                               <ZeldaIcon name="gt" title={t('tracker.config.gtCrystals')} />
+                                       </Form.Label>
+                                       <Form.Select
+                                               className="w-auto bg-dark"
+                                               name="gt-crystals"
+                                               onChange={handleConfigChange}
+                                               value={getConfigValue(config, 'gt-crystals', 7)}
+                                       >
+                                               {['?', 0, 1, 2, 3, 4, 5, 6, 7].map(n =>
+                                                       <option key={n} value={n}>
+                                                               {n}
+                                                       </option>
+                                               )}
+                                       </Form.Select>
+                               </Form.Group>
+                               <Form.Group
+                                       className="d-inline-flex align-items-center justify-content-between"
+                                       controlId="tracker.ganonCrystals"
+                               >
+                                       <Form.Label className="me-1">
+                                               <ZeldaIcon name="ganon" title={t('tracker.config.ganonCrystals')} />
+                                       </Form.Label>
+                                       <Form.Select
+                                               className="w-auto bg-dark"
+                                               name="ganon-crystals"
+                                               onChange={handleConfigChange}
+                                               value={getConfigValue(config, 'ganon-crystals', 7)}
+                                       >
+                                               {['?', 0, 1, 2, 3, 4, 5, 6, 7].map(n =>
+                                                       <option key={n} value={n}>
+                                                               {n}
+                                                       </option>
+                                               )}
+                                       </Form.Select>
+                               </Form.Group>
+                               <Form.Group
+                                       className="d-inline-flex align-items-center justify-content-between"
+                                       controlId="tracker.goal"
+                               >
+                                       <Form.Label className="me-1">
+                                               <ZeldaIcon name="triforce" title={t('tracker.config.goal')} />
+                                       </Form.Label>
+                                       <Form.Select
+                                               className="w-auto bg-dark"
+                                               name="goal"
+                                               onChange={handleConfigChange}
+                                               value={getConfigValue(config, 'goal', 'ganon')}
+                                       >
+                                               {['ganon', 'fast', 'ad', 'ped', 'trinity', 'thunt', 'ghunt'].map(n =>
+                                                       <option key={n} value={n}>
+                                                               {t(`tracker.config.goals.${n}`)}
+                                                       </option>
+                                               )}
+                                       </Form.Select>
+                               </Form.Group>
+                       </div>
+                       <div>
+                               <AutoTracking />
+                       </div>
+               </Container>
+               <ConfigDialog onHide={() => setShowConfigDialog(false)} show={showConfigDialog} />
+       </Navbar>;
+};
+
+export default Toolbar;
diff --git a/resources/js/components/tracker/index.js b/resources/js/components/tracker/index.js
deleted file mode 100644 (file)
index 68f7972..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-
-import Canvas from './Canvas';
-import Toolbar from './Toolbar';
-
-const Tracker = () => {
-       return <div className="tracker">
-               <Toolbar />
-               <Canvas />
-       </div>;
-};
-
-export default Tracker;
diff --git a/resources/js/components/tracker/index.jsx b/resources/js/components/tracker/index.jsx
new file mode 100644 (file)
index 0000000..68f7972
--- /dev/null
@@ -0,0 +1,13 @@
+import React from 'react';
+
+import Canvas from './Canvas';
+import Toolbar from './Toolbar';
+
+const Tracker = () => {
+       return <div className="tracker">
+               <Toolbar />
+               <Canvas />
+       </div>;
+};
+
+export default Tracker;
diff --git a/resources/js/components/twitch-bot/ChatSettingsForm.js b/resources/js/components/twitch-bot/ChatSettingsForm.js
deleted file mode 100644 (file)
index 24b2a0a..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import { formatTime, parseTime } from '../../helpers/Result';
-import yup from '../../schema/yup';
-
-const ChatSettingsForm = ({
-       dirty,
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       isSubmitting,
-       touched,
-       values,
-}) => {
-       const { t } = useTranslation();
-
-       return <Form noValidate onSubmit={handleSubmit}>
-               <Row>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.wait_msgs_min">
-                               <Form.Label>{t('twitchBot.chatWaitMsgsMin')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.wait_msgs_min && errors.wait_msgs_min)}
-                                       name="wait_msgs_min"
-                                       min="1"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="number"
-                                       value={values.wait_msgs_min || 1}
-                               />
-                       </Form.Group>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.wait_msgs_max">
-                               <Form.Label>{t('twitchBot.chatWaitMsgsMax')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.wait_msgs_max && errors.wait_msgs_max)}
-                                       name="wait_msgs_max"
-                                       min="1"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="number"
-                                       value={values.wait_msgs_max || 10}
-                               />
-                       </Form.Group>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.wait_time_min">
-                               <Form.Label>{t('twitchBot.chatWaitTimeMin')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.wait_time_min && errors.wait_time_min)}
-                                       name="wait_time_min"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="text"
-                                       value={values.wait_time_min || '0'}
-                               />
-                               {touched.wait_time_min && errors.wait_time_min ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.wait_time_min)}
-                                       </Form.Control.Feedback>
-                               :
-                                       <Form.Text muted>
-                                               {formatTime({ time: parseTime(values.wait_time_min)})}
-                                       </Form.Text>
-                               }
-                       </Form.Group>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.wait_time_max">
-                               <Form.Label>{t('twitchBot.chatWaitTimeMax')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.wait_time_max && errors.wait_time_max)}
-                                       name="wait_time_max"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="text"
-                                       value={values.wait_time_max || '15:00'}
-                               />
-                               {touched.wait_time_max && errors.wait_time_max ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.wait_time_max)}
-                                       </Form.Control.Feedback>
-                               :
-                                       <Form.Text muted>
-                                               {formatTime({ time: parseTime(values.wait_time_max)})}
-                                       </Form.Text>
-                               }
-                       </Form.Group>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.language">
-                               <Form.Label>{t('twitchBot.language')}</Form.Label>
-                               <Form.Select
-                                       isInvalid={!!(touched.language && errors.language)}
-                                       name="language"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.language || 'de'}
-                               >
-                                       {['de', 'en', 'es', 'fr'].map(lang =>
-                                               <option key={lang} value={lang}>
-                                                       {t(`general.languages.${lang}`)}
-                                               </option>
-                                       )}
-                               </Form.Select>
-                               {touched.language && errors.language ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.language)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.respond">
-                               <Form.Label>{t('twitchBot.respond')}</Form.Label>
-                               <Form.Select
-                                       isInvalid={!!(touched.respond && errors.respond)}
-                                       name="respond"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.respond || 'yes'}
-                               >
-                                       {['yes', '50', 'no'].map(value =>
-                                               <option key={value} value={value}>
-                                                       {t(`twitchBot.respondOptions.${value}`)}
-                                               </option>
-                                       )}
-                               </Form.Select>
-                               {touched.respond && errors.respond ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.respond)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.min_age">
-                               <Form.Label>{t('twitchBot.chatMinAge')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.min_age && errors.min_age)}
-                                       name="min_age"
-                                       min="1"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="number"
-                                       value={values.min_age || 1}
-                               />
-                       </Form.Group>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.source">
-                               <Form.Label>{t('twitchBot.chatSource')}</Form.Label>
-                               <Form.Select
-                                       isInvalid={!!(touched.source && errors.source)}
-                                       name="source"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.source || 'any'}
-                               >
-                                       {['any', 'cat', 'chan', 'catchan'].map(value =>
-                                               <option key={value} value={value}>
-                                                       {t(`twitchBot.chatSources.${value}`)}
-                                               </option>
-                                       )}
-                               </Form.Select>
-                               {touched.respond && errors.respond ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.respond)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group as={Col} md={6} controlId="chatSettings.adlib">
-                               <Form.Label>{t('twitchBot.chatAdlibChance')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.adlib && errors.adlib)}
-                                       name="adlib"
-                                       min="0"
-                                       max="100"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       type="number"
-                                       value={values.adlib || 1}
-                               />
-                       </Form.Group>
-               </Row>
-               <div className="button-bar mt-3">
-                       <Button disabled={!dirty || isSubmitting} type="submit" variant="primary">
-                               {t('button.save')}
-                       </Button>
-               </div>
-       </Form>;
-};
-
-ChatSettingsForm.propTypes = {
-       dirty: PropTypes.bool,
-       errors: PropTypes.shape({
-               adlib: PropTypes.string,
-               language: PropTypes.string,
-               min_age: PropTypes.string,
-               respond: PropTypes.string,
-               source: PropTypes.string,
-               wait_msgs_max: PropTypes.string,
-               wait_msgs_min: PropTypes.string,
-               wait_time_min: PropTypes.string,
-               wait_time_max: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       isSubmitting: PropTypes.bool,
-       touched: PropTypes.shape({
-               adlib: PropTypes.bool,
-               language: PropTypes.bool,
-               min_age: PropTypes.bool,
-               respond: PropTypes.bool,
-               source: PropTypes.bool,
-               wait_msgs_max: PropTypes.bool,
-               wait_msgs_min: PropTypes.bool,
-               wait_time_min: PropTypes.bool,
-               wait_time_max: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               adlib: PropTypes.number,
-               language: PropTypes.string,
-               min_age: PropTypes.number,
-               respond: PropTypes.string,
-               source: PropTypes.string,
-               wait_msgs_max: PropTypes.number,
-               wait_msgs_min: PropTypes.number,
-               wait_time_min: PropTypes.string,
-               wait_time_max: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'ChatSettingsForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { onSubmit } = actions.props;
-               await onSubmit({
-                       ...values,
-                       wait_time_min: parseTime(values.wait_time_min) || 0,
-                       wait_time_max: parseTime(values.wait_time_max) || 0,
-               });
-       },
-       mapPropsToValues: ({ channel }) => ({
-               adlib: channel.chat_settings.adlib || 50,
-               language: channel.chat_settings.language || channel.languages[0] || 'de',
-               min_age: channel.chat_settings.min_age || 1,
-               respond: channel.chat_settings.respond || 'yes',
-               source: channel.chat_settings.source || 'any',
-               wait_msgs_min: channel.chat_settings.wait_msgs_min || 1,
-               wait_msgs_max: channel.chat_settings.wait_msgs_max || 10,
-               wait_time_min: channel.chat_settings.wait_time_min
-                       ? formatTime({ time: channel.chat_settings.wait_time_min }) : '0',
-               wait_time_max: channel.chat_settings.wait_time_max
-                       ? formatTime({ time: channel.chat_settings.wait_time_max }) : '15:00',
-       }),
-       validationSchema: yup.object().shape({
-               adlib: yup.number().min(0).max(100),
-               language: yup.string(),
-               min_age: yup.number().min(1),
-               respond: yup.string(),
-               wait_msgs_min: yup.number().min(1),
-               wait_msgs_max: yup.number().min(1),
-               wait_time_min: yup.string().time(),
-               wait_time_max: yup.string().time(),
-       }),
-})(ChatSettingsForm);
diff --git a/resources/js/components/twitch-bot/ChatSettingsForm.jsx b/resources/js/components/twitch-bot/ChatSettingsForm.jsx
new file mode 100644 (file)
index 0000000..5810a3f
--- /dev/null
@@ -0,0 +1,262 @@
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import { formatTime, parseTime } from '../../helpers/Result';
+import yup from '../../schema/yup';
+
+const ChatSettingsForm = ({
+       dirty,
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       isSubmitting,
+       touched,
+       values,
+}) => {
+       const { t } = useTranslation();
+
+       return <Form noValidate onSubmit={handleSubmit}>
+               <Row>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.wait_msgs_min">
+                               <Form.Label>{t('twitchBot.chatWaitMsgsMin')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.wait_msgs_min && errors.wait_msgs_min)}
+                                       name="wait_msgs_min"
+                                       min="1"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="number"
+                                       value={values.wait_msgs_min || 1}
+                               />
+                       </Form.Group>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.wait_msgs_max">
+                               <Form.Label>{t('twitchBot.chatWaitMsgsMax')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.wait_msgs_max && errors.wait_msgs_max)}
+                                       name="wait_msgs_max"
+                                       min="1"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="number"
+                                       value={values.wait_msgs_max || 10}
+                               />
+                       </Form.Group>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.wait_time_min">
+                               <Form.Label>{t('twitchBot.chatWaitTimeMin')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.wait_time_min && errors.wait_time_min)}
+                                       name="wait_time_min"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="text"
+                                       value={values.wait_time_min || '0'}
+                               />
+                               {touched.wait_time_min && errors.wait_time_min ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.wait_time_min)}
+                                       </Form.Control.Feedback>
+                               :
+                                       <Form.Text muted>
+                                               {formatTime({ time: parseTime(values.wait_time_min)})}
+                                       </Form.Text>
+                               }
+                       </Form.Group>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.wait_time_max">
+                               <Form.Label>{t('twitchBot.chatWaitTimeMax')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.wait_time_max && errors.wait_time_max)}
+                                       name="wait_time_max"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="text"
+                                       value={values.wait_time_max || '15:00'}
+                               />
+                               {touched.wait_time_max && errors.wait_time_max ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.wait_time_max)}
+                                       </Form.Control.Feedback>
+                               :
+                                       <Form.Text muted>
+                                               {formatTime({ time: parseTime(values.wait_time_max)})}
+                                       </Form.Text>
+                               }
+                       </Form.Group>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.language">
+                               <Form.Label>{t('twitchBot.language')}</Form.Label>
+                               <Form.Select
+                                       isInvalid={!!(touched.language && errors.language)}
+                                       name="language"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.language || 'de'}
+                               >
+                                       {['de', 'en', 'es', 'fr'].map(lang =>
+                                               <option key={lang} value={lang}>
+                                                       {t(`general.languages.${lang}`)}
+                                               </option>
+                                       )}
+                               </Form.Select>
+                               {touched.language && errors.language ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.language)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.respond">
+                               <Form.Label>{t('twitchBot.respond')}</Form.Label>
+                               <Form.Select
+                                       isInvalid={!!(touched.respond && errors.respond)}
+                                       name="respond"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.respond || 'yes'}
+                               >
+                                       {['yes', '50', 'no'].map(value =>
+                                               <option key={value} value={value}>
+                                                       {t(`twitchBot.respondOptions.${value}`)}
+                                               </option>
+                                       )}
+                               </Form.Select>
+                               {touched.respond && errors.respond ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.respond)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.min_age">
+                               <Form.Label>{t('twitchBot.chatMinAge')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.min_age && errors.min_age)}
+                                       name="min_age"
+                                       min="1"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="number"
+                                       value={values.min_age || 1}
+                               />
+                       </Form.Group>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.source">
+                               <Form.Label>{t('twitchBot.chatSource')}</Form.Label>
+                               <Form.Select
+                                       isInvalid={!!(touched.source && errors.source)}
+                                       name="source"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.source || 'any'}
+                               >
+                                       {['any', 'cat', 'chan', 'catchan'].map(value =>
+                                               <option key={value} value={value}>
+                                                       {t(`twitchBot.chatSources.${value}`)}
+                                               </option>
+                                       )}
+                               </Form.Select>
+                               {touched.respond && errors.respond ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.respond)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group as={Col} md={6} controlId="chatSettings.adlib">
+                               <Form.Label>{t('twitchBot.chatAdlibChance')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.adlib && errors.adlib)}
+                                       name="adlib"
+                                       min="0"
+                                       max="100"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       type="number"
+                                       value={Object.prototype.hasOwnProperty.call(values, 'adlib')
+                                               ? values.adlib : 50}
+                               />
+                       </Form.Group>
+               </Row>
+               <div className="button-bar mt-3">
+                       <Button disabled={!dirty || isSubmitting} type="submit" variant="primary">
+                               {t('button.save')}
+                       </Button>
+               </div>
+       </Form>;
+};
+
+ChatSettingsForm.propTypes = {
+       dirty: PropTypes.bool,
+       errors: PropTypes.shape({
+               adlib: PropTypes.string,
+               language: PropTypes.string,
+               min_age: PropTypes.string,
+               respond: PropTypes.string,
+               source: PropTypes.string,
+               wait_msgs_max: PropTypes.string,
+               wait_msgs_min: PropTypes.string,
+               wait_time_min: PropTypes.string,
+               wait_time_max: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       isSubmitting: PropTypes.bool,
+       touched: PropTypes.shape({
+               adlib: PropTypes.bool,
+               language: PropTypes.bool,
+               min_age: PropTypes.bool,
+               respond: PropTypes.bool,
+               source: PropTypes.bool,
+               wait_msgs_max: PropTypes.bool,
+               wait_msgs_min: PropTypes.bool,
+               wait_time_min: PropTypes.bool,
+               wait_time_max: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               adlib: PropTypes.number,
+               language: PropTypes.string,
+               min_age: PropTypes.number,
+               respond: PropTypes.string,
+               source: PropTypes.string,
+               wait_msgs_max: PropTypes.number,
+               wait_msgs_min: PropTypes.number,
+               wait_time_min: PropTypes.string,
+               wait_time_max: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'ChatSettingsForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { onSubmit } = actions.props;
+               await onSubmit({
+                       ...values,
+                       wait_time_min: parseTime(values.wait_time_min) || 0,
+                       wait_time_max: parseTime(values.wait_time_max) || 0,
+               });
+       },
+       mapPropsToValues: ({ channel }) => ({
+               adlib: Object.prototype.hasOwnProperty.call(channel.chat_settings, 'adlib')
+                       ? channel.chat_settings.adlib : 50,
+               language: channel.chat_settings.language || channel.languages[0] || 'de',
+               min_age: channel.chat_settings.min_age || 1,
+               respond: channel.chat_settings.respond || 'yes',
+               source: channel.chat_settings.source || 'any',
+               wait_msgs_min: channel.chat_settings.wait_msgs_min || 1,
+               wait_msgs_max: channel.chat_settings.wait_msgs_max || 10,
+               wait_time_min: channel.chat_settings.wait_time_min
+                       ? formatTime({ time: channel.chat_settings.wait_time_min }) : '0',
+               wait_time_max: channel.chat_settings.wait_time_max
+                       ? formatTime({ time: channel.chat_settings.wait_time_max }) : '15:00',
+       }),
+       validationSchema: yup.object().shape({
+               adlib: yup.number().min(0).max(100),
+               language: yup.string(),
+               min_age: yup.number().min(1),
+               respond: yup.string(),
+               wait_msgs_min: yup.number().min(1),
+               wait_msgs_max: yup.number().min(1),
+               wait_time_min: yup.string().time(),
+               wait_time_max: yup.string().time(),
+       }),
+})(ChatSettingsForm);
diff --git a/resources/js/components/twitch-bot/Command.js b/resources/js/components/twitch-bot/Command.js
deleted file mode 100644 (file)
index 9122086..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from '../common/Icon';
-
-const Command = ({
-       name,
-       onEditCommand,
-       onRemoveCommand,
-       settings,
-}) => {
-       const { t } = useTranslation();
-
-       const type = (settings && settings.command) || 'none';
-
-       return <tr>
-               <td>{`!${name}`}</td>
-               <td>{t(`twitchBot.commandRestrictions.${(settings && settings.restrict) || 'none'}`)}</td>
-               <td>{t(`twitchBot.commandTypes.${type}`)}</td>
-               <td className="text-end">
-                       <div className="button-bar">
-                               {onEditCommand ?
-                                       <Button
-                                               onClick={() => onEditCommand(name, settings)}
-                                               title={t('button.edit')}
-                                               variant="outline-secondary"
-                                       >
-                                               <Icon.EDIT title="" />
-                                       </Button>
-                               : null}
-                               {onRemoveCommand ?
-                                       <Button
-                                               onClick={() => onRemoveCommand(name)}
-                                               title={t('button.remove')}
-                                               variant="outline-danger"
-                                       >
-                                               <Icon.REMOVE title="" />
-                                       </Button>
-                               : null}
-                       </div>
-               </td>
-       </tr>;
-};
-
-Command.propTypes = {
-       name: PropTypes.string,
-       onEditCommand: PropTypes.func,
-       onRemoveCommand: PropTypes.func,
-       settings: PropTypes.shape({
-               command: PropTypes.string,
-               restrict: PropTypes.string,
-       }),
-};
-
-export default Command;
diff --git a/resources/js/components/twitch-bot/Command.jsx b/resources/js/components/twitch-bot/Command.jsx
new file mode 100644 (file)
index 0000000..9122086
--- /dev/null
@@ -0,0 +1,57 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../common/Icon';
+
+const Command = ({
+       name,
+       onEditCommand,
+       onRemoveCommand,
+       settings,
+}) => {
+       const { t } = useTranslation();
+
+       const type = (settings && settings.command) || 'none';
+
+       return <tr>
+               <td>{`!${name}`}</td>
+               <td>{t(`twitchBot.commandRestrictions.${(settings && settings.restrict) || 'none'}`)}</td>
+               <td>{t(`twitchBot.commandTypes.${type}`)}</td>
+               <td className="text-end">
+                       <div className="button-bar">
+                               {onEditCommand ?
+                                       <Button
+                                               onClick={() => onEditCommand(name, settings)}
+                                               title={t('button.edit')}
+                                               variant="outline-secondary"
+                                       >
+                                               <Icon.EDIT title="" />
+                                       </Button>
+                               : null}
+                               {onRemoveCommand ?
+                                       <Button
+                                               onClick={() => onRemoveCommand(name)}
+                                               title={t('button.remove')}
+                                               variant="outline-danger"
+                                       >
+                                               <Icon.REMOVE title="" />
+                                       </Button>
+                               : null}
+                       </div>
+               </td>
+       </tr>;
+};
+
+Command.propTypes = {
+       name: PropTypes.string,
+       onEditCommand: PropTypes.func,
+       onRemoveCommand: PropTypes.func,
+       settings: PropTypes.shape({
+               command: PropTypes.string,
+               restrict: PropTypes.string,
+       }),
+};
+
+export default Command;
diff --git a/resources/js/components/twitch-bot/CommandDialog.js b/resources/js/components/twitch-bot/CommandDialog.js
deleted file mode 100644 (file)
index 7e8ce16..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import CommandForm from './CommandForm';
-
-const CommandDialog = ({
-       name,
-       onHide,
-       onSubmit,
-       settings,
-       show,
-}) => {
-       const { t } = useTranslation();
-
-       return <Modal className="report-dialog" onHide={onHide} show={show}>
-               <Modal.Header closeButton>
-                       <Modal.Title>
-                               {t(name ? 'twitchBot.commandDialog' : 'twitchBot.addCommand')}
-                       </Modal.Title>
-               </Modal.Header>
-               <CommandForm
-                       name={name}
-                       onCancel={onHide}
-                       onSubmit={onSubmit}
-                       settings={settings}
-               />
-       </Modal>;
-};
-
-CommandDialog.propTypes = {
-       name: PropTypes.string,
-       onHide: PropTypes.func,
-       onSubmit: PropTypes.func,
-       settings: PropTypes.shape({
-       }),
-       show: PropTypes.bool,
-};
-
-export default CommandDialog;
diff --git a/resources/js/components/twitch-bot/CommandDialog.jsx b/resources/js/components/twitch-bot/CommandDialog.jsx
new file mode 100644 (file)
index 0000000..7e8ce16
--- /dev/null
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import CommandForm from './CommandForm';
+
+const CommandDialog = ({
+       name,
+       onHide,
+       onSubmit,
+       settings,
+       show,
+}) => {
+       const { t } = useTranslation();
+
+       return <Modal className="report-dialog" onHide={onHide} show={show}>
+               <Modal.Header closeButton>
+                       <Modal.Title>
+                               {t(name ? 'twitchBot.commandDialog' : 'twitchBot.addCommand')}
+                       </Modal.Title>
+               </Modal.Header>
+               <CommandForm
+                       name={name}
+                       onCancel={onHide}
+                       onSubmit={onSubmit}
+                       settings={settings}
+               />
+       </Modal>;
+};
+
+CommandDialog.propTypes = {
+       name: PropTypes.string,
+       onHide: PropTypes.func,
+       onSubmit: PropTypes.func,
+       settings: PropTypes.shape({
+       }),
+       show: PropTypes.bool,
+};
+
+export default CommandDialog;
diff --git a/resources/js/components/twitch-bot/CommandForm.js b/resources/js/components/twitch-bot/CommandForm.js
deleted file mode 100644 (file)
index d922170..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Form, Modal } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import yup from '../../schema/yup';
-
-const CommandForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       name,
-       onCancel,
-       touched,
-       values,
-}) => {
-       const { t } = useTranslation();
-
-       const COMMANDS = [
-               'none',
-               'runner',
-               'crew',
-               'guessing-start',
-               'guessing-stop',
-               'guessing-solve',
-               'guessing-cancel',
-               'guessing-leaderboard',
-       ];
-       const RESTRICTIONS = [
-               'none',
-               'mod',
-               'owner',
-       ];
-
-       return <Form noValidate onSubmit={handleSubmit}>
-               <Modal.Body>
-                       <Form.Group controlId="command.name">
-                               <Form.Label>{t('twitchBot.commandName')}</Form.Label>
-                               <Form.Control
-                                       disabled={!!name}
-                                       isInvalid={!!(touched.name && errors.name)}
-                                       name="name"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       plaintext={!!name}
-                                       readOnly={!!name}
-                                       type="text"
-                                       value={values.name || ''}
-                               />
-                               {touched.name && errors.name ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.name)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group controlId="command.restrict">
-                               <Form.Label>{t('twitchBot.commandRestriction')}</Form.Label>
-                               <Form.Select
-                                       isInvalid={!!(touched.restrict && errors.restrict)}
-                                       name="restrict"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.restrict || 'none'}
-                               >
-                                       {RESTRICTIONS.map(r =>
-                                               <option key={r} value={r}>
-                                                       {t(`twitchBot.commandRestrictions.${r}`)}
-                                               </option>
-                                       )}
-                               </Form.Select>
-                               {touched.restrict && errors.restrict ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.restrict)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group controlId="command.command">
-                               <Form.Label>{t('twitchBot.commandType')}</Form.Label>
-                               <Form.Select
-                                       isInvalid={!!(touched.command && errors.command)}
-                                       name="command"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.command || 'none'}
-                               >
-                                       {COMMANDS.map(c =>
-                                               <option key={c} value={c}>
-                                                       {t(`twitchBot.commandTypes.${c}`)}
-                                               </option>
-                                       )}
-                               </Form.Select>
-                               {touched.command && errors.command ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.command)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Modal.Body>
-               <Modal.Footer>
-                       {onCancel ?
-                               <Button onClick={onCancel} variant="secondary">
-                                       {t('button.cancel')}
-                               </Button>
-                       : null}
-                       <Button type="submit" variant="primary">
-                               {t('button.save')}
-                       </Button>
-               </Modal.Footer>
-       </Form>;
-};
-
-CommandForm.propTypes = {
-       errors: PropTypes.shape({
-               command: PropTypes.string,
-               name: PropTypes.string,
-               restrict: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       name: PropTypes.string,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               command: PropTypes.bool,
-               name: PropTypes.bool,
-               restrict: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               command: PropTypes.string,
-               name: PropTypes.string,
-               restrict: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'CommandForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { setErrors } = actions;
-               const { onSubmit } = actions.props;
-               try {
-                       await onSubmit(values);
-               } catch (e) {
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ name, settings }) => {
-               return {
-                       command: (settings && settings.command) || 'none',
-                       name: name || '',
-                       restrict: (settings && settings.restrict) || 'none',
-               };
-       },
-       validationSchema: yup.object().shape({
-               command: yup.string(),
-               name: yup.string().required(),
-               restrict: yup.string(),
-       }),
-})(CommandForm);
diff --git a/resources/js/components/twitch-bot/CommandForm.jsx b/resources/js/components/twitch-bot/CommandForm.jsx
new file mode 100644 (file)
index 0000000..d922170
--- /dev/null
@@ -0,0 +1,164 @@
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Form, Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import yup from '../../schema/yup';
+
+const CommandForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       name,
+       onCancel,
+       touched,
+       values,
+}) => {
+       const { t } = useTranslation();
+
+       const COMMANDS = [
+               'none',
+               'runner',
+               'crew',
+               'guessing-start',
+               'guessing-stop',
+               'guessing-solve',
+               'guessing-cancel',
+               'guessing-leaderboard',
+       ];
+       const RESTRICTIONS = [
+               'none',
+               'mod',
+               'owner',
+       ];
+
+       return <Form noValidate onSubmit={handleSubmit}>
+               <Modal.Body>
+                       <Form.Group controlId="command.name">
+                               <Form.Label>{t('twitchBot.commandName')}</Form.Label>
+                               <Form.Control
+                                       disabled={!!name}
+                                       isInvalid={!!(touched.name && errors.name)}
+                                       name="name"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       plaintext={!!name}
+                                       readOnly={!!name}
+                                       type="text"
+                                       value={values.name || ''}
+                               />
+                               {touched.name && errors.name ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.name)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group controlId="command.restrict">
+                               <Form.Label>{t('twitchBot.commandRestriction')}</Form.Label>
+                               <Form.Select
+                                       isInvalid={!!(touched.restrict && errors.restrict)}
+                                       name="restrict"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.restrict || 'none'}
+                               >
+                                       {RESTRICTIONS.map(r =>
+                                               <option key={r} value={r}>
+                                                       {t(`twitchBot.commandRestrictions.${r}`)}
+                                               </option>
+                                       )}
+                               </Form.Select>
+                               {touched.restrict && errors.restrict ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.restrict)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group controlId="command.command">
+                               <Form.Label>{t('twitchBot.commandType')}</Form.Label>
+                               <Form.Select
+                                       isInvalid={!!(touched.command && errors.command)}
+                                       name="command"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.command || 'none'}
+                               >
+                                       {COMMANDS.map(c =>
+                                               <option key={c} value={c}>
+                                                       {t(`twitchBot.commandTypes.${c}`)}
+                                               </option>
+                                       )}
+                               </Form.Select>
+                               {touched.command && errors.command ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.command)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Modal.Body>
+               <Modal.Footer>
+                       {onCancel ?
+                               <Button onClick={onCancel} variant="secondary">
+                                       {t('button.cancel')}
+                               </Button>
+                       : null}
+                       <Button type="submit" variant="primary">
+                               {t('button.save')}
+                       </Button>
+               </Modal.Footer>
+       </Form>;
+};
+
+CommandForm.propTypes = {
+       errors: PropTypes.shape({
+               command: PropTypes.string,
+               name: PropTypes.string,
+               restrict: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       name: PropTypes.string,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               command: PropTypes.bool,
+               name: PropTypes.bool,
+               restrict: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               command: PropTypes.string,
+               name: PropTypes.string,
+               restrict: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'CommandForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { setErrors } = actions;
+               const { onSubmit } = actions.props;
+               try {
+                       await onSubmit(values);
+               } catch (e) {
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ name, settings }) => {
+               return {
+                       command: (settings && settings.command) || 'none',
+                       name: name || '',
+                       restrict: (settings && settings.restrict) || 'none',
+               };
+       },
+       validationSchema: yup.object().shape({
+               command: yup.string(),
+               name: yup.string().required(),
+               restrict: yup.string(),
+       }),
+})(CommandForm);
diff --git a/resources/js/components/twitch-bot/Commands.js b/resources/js/components/twitch-bot/Commands.js
deleted file mode 100644 (file)
index 98600d0..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Table } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Command from './Command';
-
-const Commands = ({
-       channel,
-       onEditCommand,
-       onRemoveCommand,
-}) => {
-       const { t } = useTranslation();
-
-       return channel.chat_commands ?
-               <Table>
-                       <thead>
-                               <tr>
-                                       <th>{t('twitchBot.commandName')}</th>
-                                       <th>{t('twitchBot.commandRestriction')}</th>
-                                       <th>{t('twitchBot.commandType')}</th>
-                                       <th className="text-end">{t('general.actions')}</th>
-                               </tr>
-                       </thead>
-                       <tbody>
-                               {Object.entries(channel.chat_commands).map(([name, settings]) =>
-                                       <Command
-                                               key={name}
-                                               name={name}
-                                               onEditCommand={onEditCommand}
-                                               onRemoveCommand={onRemoveCommand}
-                                               settings={settings}
-                                       />
-                               )}
-                       </tbody>
-               </Table>
-       : null;
-};
-
-Commands.propTypes = {
-       channel: PropTypes.shape({
-               chat_commands: PropTypes.shape({
-               }),
-       }),
-       onEditCommand: PropTypes.func,
-       onRemoveCommand: PropTypes.func,
-};
-
-export default Commands;
diff --git a/resources/js/components/twitch-bot/Commands.jsx b/resources/js/components/twitch-bot/Commands.jsx
new file mode 100644 (file)
index 0000000..98600d0
--- /dev/null
@@ -0,0 +1,49 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Table } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Command from './Command';
+
+const Commands = ({
+       channel,
+       onEditCommand,
+       onRemoveCommand,
+}) => {
+       const { t } = useTranslation();
+
+       return channel.chat_commands ?
+               <Table>
+                       <thead>
+                               <tr>
+                                       <th>{t('twitchBot.commandName')}</th>
+                                       <th>{t('twitchBot.commandRestriction')}</th>
+                                       <th>{t('twitchBot.commandType')}</th>
+                                       <th className="text-end">{t('general.actions')}</th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                               {Object.entries(channel.chat_commands).map(([name, settings]) =>
+                                       <Command
+                                               key={name}
+                                               name={name}
+                                               onEditCommand={onEditCommand}
+                                               onRemoveCommand={onRemoveCommand}
+                                               settings={settings}
+                                       />
+                               )}
+                       </tbody>
+               </Table>
+       : null;
+};
+
+Commands.propTypes = {
+       channel: PropTypes.shape({
+               chat_commands: PropTypes.shape({
+               }),
+       }),
+       onEditCommand: PropTypes.func,
+       onRemoveCommand: PropTypes.func,
+};
+
+export default Commands;
diff --git a/resources/js/components/twitch-bot/Controls.js b/resources/js/components/twitch-bot/Controls.js
deleted file mode 100644 (file)
index 394f546..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-import axios from 'axios';
-import React from 'react';
-import { Alert, Button, Col, Form, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import ChatSettingsForm from './ChatSettingsForm';
-import CommandDialog from './CommandDialog';
-import Commands from './Commands';
-import GuessingSettingsForm from './GuessingSettingsForm';
-import ChatBotLog from '../chat-bot-logs/ChatBotLog';
-import ChannelSelect from '../common/ChannelSelect';
-import Icon from '../common/Icon';
-import ToggleSwitch from '../common/ToggleSwitch';
-
-const CHAT_CATEGORIES = [
-       'unclassified',
-       'hi',
-       'gl',
-       'gg',
-       'eyes',
-       'love',
-       'lol',
-       'yes',
-       'no',
-       'rage',
-       'sad',
-       'sweat',
-       'wtf',
-       'pog',
-       'hype',
-       'kappa',
-       'o7',
-       'question',
-       'thx',
-];
-
-const Controls = () => {
-       const [channel, setChannel] = React.useState(null);
-       const [chatText, setChatText] = React.useState('');
-       const [editCommand, setEditCommand] = React.useState('');
-       const [editCommandSettings, setEditCommandSettings] = React.useState({});
-       const [showCommandDialog, setShowCommandDialog] = React.useState(false);
-
-       const { t } = useTranslation();
-
-       const chat = React.useCallback(async (text, bot_nick) => {
-               try {
-                       await axios.post(`/api/channels/${channel.id}/chat`, {
-                               text,
-                               bot_nick,
-                       });
-                       toastr.success(t('twitchBot.chatSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.chatError'));
-               }
-       }, [channel, chatText, t]);
-
-       const randomChat = React.useCallback(async (category) => {
-               try {
-                       await axios.post(`/api/channels/${channel.id}/chat`, {
-                               bot_nick: 'horstiebot',
-                               category,
-                       });
-                       toastr.success(t('twitchBot.chatSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.chatError'));
-               }
-       }, [channel, chatText, t]);
-
-       const adlibChat = React.useCallback(async () => {
-               try {
-                       await axios.post(`/api/channels/${channel.id}/chat`, {
-                               bot_nick: 'horstiebot',
-                               adlib: true,
-                       });
-                       toastr.success(t('twitchBot.chatSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.chatError'));
-               }
-       }, [channel, chatText, t]);
-
-       const join = React.useCallback(async (bot_nick) => {
-               try {
-                       const rsp = await axios.post(`/api/channels/${channel.id}/join`, { bot_nick });
-                       setChannel(rsp.data);
-                       toastr.success(t('twitchBot.joinSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.joinError'));
-               }
-       }, [channel, t]);
-
-       const part = React.useCallback(async (bot_nick) => {
-               try {
-                       const rsp = await axios.post(`/api/channels/${channel.id}/part`, { bot_nick });
-                       setChannel(rsp.data);
-                       toastr.success(t('twitchBot.partSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.partError'));
-               }
-       }, [channel, t]);
-
-       const saveChatSettings = React.useCallback(async (values) => {
-               try {
-                       const rsp = await axios.post(`/api/channels/${channel.id}/chat-settings`, values);
-                       setChannel(rsp.data);
-                       toastr.success(t('twitchBot.saveSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.saveError'));
-               }
-       }, [channel, t]);
-
-       const onAddCommand = React.useCallback(() => {
-               setEditCommand('');
-               setEditCommandSettings({});
-               setShowCommandDialog(true);
-       }, [channel]);
-
-       const onEditCommand = React.useCallback((name, settings) => {
-               setEditCommand(name);
-               setEditCommandSettings(settings);
-               setShowCommandDialog(true);
-       }, [channel]);
-
-       const onRemoveCommand = React.useCallback(async (name) => {
-               try {
-                       const rsp = await axios.delete(`/api/channels/${channel.id}/commands/${name}`);
-                       setChannel(rsp.data);
-                       toastr.success(t('twitchBot.saveSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.saveError'));
-               }
-       }, [channel]);
-
-       const saveCommand = React.useCallback(async (values) => {
-               try {
-                       const rsp = await axios.put(
-                               `/api/channels/${channel.id}/commands/${values.name}`,
-                               values,
-                       );
-                       setChannel(rsp.data);
-                       setShowCommandDialog(false);
-                       setEditCommand('');
-                       setEditCommandSettings({});
-                       toastr.success(t('twitchBot.saveSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.saveError'));
-                       throw e;
-               }
-       }, [channel]);
-
-       const saveGuessingGame = React.useCallback(async (values) => {
-               try {
-                       const rsp = await axios.put(
-                               `/api/channels/${channel.id}/guessing-game/${values.name}`,
-                               values,
-                       );
-                       setChannel(rsp.data);
-                       toastr.success(t('twitchBot.saveSuccess'));
-               } catch (e) {
-                       toastr.error(t('twitchBot.saveError'));
-                       throw e;
-               }
-       }, [channel]);
-
-       return <>
-               <Row className="mb-4">
-                       <Form.Group as={Col} md={6}>
-                               <Form.Label>{t('twitchBot.channel')}</Form.Label>
-                               <Form.Control
-                                       as={ChannelSelect}
-                                       autoSelect
-                                       joinable
-                                       manageable
-                                       onChange={({ channel }) => { setChannel(channel); }}
-                                       value={channel ? channel.id : ''}
-                               />
-                       </Form.Group>
-                       {channel ? <>
-                               <Form.Group as={Col} md={3}>
-                                       <Form.Label>{t('twitchBot.joinApp')}</Form.Label>
-                                       <div>
-                                               <Form.Control
-                                                       as={ToggleSwitch}
-                                                       onChange={({ target: { value } }) => {
-                                                               if (value) {
-                                                                       join('localhorsttv');
-                                                               } else {
-                                                                       part('localhorsttv');
-                                                               }
-                                                       }}
-                                                       value={channel.join}
-                                               />
-                                       </div>
-                               </Form.Group>
-                               <Form.Group as={Col} md={3}>
-                                       <Form.Label>{t('twitchBot.joinChat')}</Form.Label>
-                                       <div>
-                                               <Form.Control
-                                                       as={ToggleSwitch}
-                                                       onChange={({ target: { value } }) => {
-                                                               if (value) {
-                                                                       join('horstiebot');
-                                                               } else {
-                                                                       part('horstiebot');
-                                                               }
-                                                       }}
-                                                       value={channel.chat}
-                                               />
-                                       </div>
-                               </Form.Group>
-                       </> : null}
-               </Row>
-               {channel ?
-                       <Row>
-                               <Col className="mt-5" md={6}>
-                                       <h3>{t('twitchBot.chat')}</h3>
-                                       <Form.Group>
-                                               <Form.Label>{t('twitchBot.chat')}</Form.Label>
-                                               <Form.Control
-                                                       as="textarea"
-                                                       onChange={({ target: { value } }) => {
-                                                               setChatText(value);
-                                                       }}
-                                                       value={chatText}
-                                               />
-                                               <div className="button-bar">
-                                                       <Button
-                                                               className="mt-2"
-                                                               disabled={!chatText || !channel.join}
-                                                               onClick={() => {
-                                                                       if (chatText) chat(chatText, 'localhorsttv');
-                                                               }}
-                                                               variant="twitch"
-                                                       >
-                                                               {t('twitchBot.sendApp')}
-                                                       </Button>
-                                                       <Button
-                                                               className="mt-2"
-                                                               disabled={!chatText || !channel.chat}
-                                                               onClick={() => {
-                                                                       if (chatText) chat(chatText, 'horstiebot');
-                                                               }}
-                                                               variant="twitch"
-                                                       >
-                                                               {t('twitchBot.sendChat')}
-                                                       </Button>
-                                               </div>
-                                       </Form.Group>
-                                       <h3 className="mt-3">{t('twitchBot.randomChat')}</h3>
-                                       <div className="button-bar">
-                                               {CHAT_CATEGORIES.map(category =>
-                                                       <Button
-                                                               key={category}
-                                                               onClick={() => { randomChat(category); }}
-                                                               variant="outline-secondary"
-                                                       >
-                                                               {t(`twitchBot.chatCategories.${category}`)}
-                                                       </Button>
-                                               )}
-                                       </div>
-                                       <div className="mt-3">
-                                               <Button
-                                                       onClick={() => { adlibChat(); }}
-                                                       title={t('twitchBot.adlibChatDesc')}
-                                                       variant="outline-secondary"
-                                               >
-                                                       {t('twitchBot.adlibChat')}
-                                               </Button>
-                                               <p className="text-muted">{t('twitchBot.adlibChatNote')}</p>
-                                       </div>
-                               </Col>
-                               <Col className="mt-5" md={6}>
-                                       <div className="d-flex justify-content-between">
-                                               <h3>{t('twitchBot.chatSettings')}</h3>
-                                               <div className="button-bar">
-                                                       <ChatBotLog id={channel.id} />
-                                               </div>
-                                       </div>
-                                       <ChatSettingsForm channel={channel} onSubmit={saveChatSettings} />
-                               </Col>
-                               <Col className="mt-5" md={12}>
-                                       <h3>{t('twitchBot.commands')}</h3>
-                                       <Commands
-                                               channel={channel}
-                                               onEditCommand={onEditCommand}
-                                               onRemoveCommand={onRemoveCommand}
-                                       />
-                                       <CommandDialog
-                                               name={editCommand}
-                                               onHide={() => {
-                                                       setShowCommandDialog(false);
-                                                       setEditCommand('');
-                                                       setEditCommandSettings({});
-                                               }}
-                                               onSubmit={saveCommand}
-                                               settings={editCommandSettings}
-                                               show={showCommandDialog}
-                                       />
-                                       <div>
-                                               <Button onClick={onAddCommand} variant="primary">
-                                                       {t('twitchBot.addCommand')}
-                                               </Button>
-                                       </div>
-                               </Col>
-                               <Col className="mt-5" md={12}>
-                                       <div className="d-flex align-items-end justify-content-between">
-                                               <h3>{t('twitchBot.guessingGame.settings')}</h3>
-                                               <div className="button-bar">
-                                                       {channel.access_key ?
-                                                               <Button
-                                                                       href={`/guessing-game/monitor/${channel.access_key}`}
-                                                                       target="_blank"
-                                                                       title={t('button.browserSource')}
-                                                                       variant="outline-secondary"
-                                                               >
-                                                                       <Icon.BROWSER_SOURCE title="" />
-                                                               </Button>
-                                                       : null}
-                                                       <Button
-                                                               onClick={() => {
-                                                                       window.open(
-                                                                               `/guessing-game/controls/${channel.id}`,
-                                                                               '',
-                                                                               'width=640,height=800,titlebar=0,menubar=0,toolbar=0',
-                                                                       );
-                                                               }}
-                                                               title={t('twitchBot.guessingGame.popoutControls')}
-                                                               variant="outline-secondary"
-                                                       >
-                                                               <Icon.OPEN title="" />
-                                                       </Button>
-                                               </div>
-                                       </div>
-                                       <GuessingSettingsForm
-                                               name="gtbk"
-                                               onSubmit={saveGuessingGame}
-                                               settings={channel.guessing_settings?.gtbk || {}}
-                                       />
-                               </Col>
-                       </Row>
-               :
-                       <Alert variant="info">
-                               {t('twitchBot.selectChannel')}
-                       </Alert>
-               }
-       </>;
-};
-
-export default Controls;
diff --git a/resources/js/components/twitch-bot/Controls.jsx b/resources/js/components/twitch-bot/Controls.jsx
new file mode 100644 (file)
index 0000000..55cbd00
--- /dev/null
@@ -0,0 +1,350 @@
+import axios from 'axios';
+import React from 'react';
+import { Alert, Button, Col, Form, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import ChatSettingsForm from './ChatSettingsForm';
+import CommandDialog from './CommandDialog';
+import Commands from './Commands';
+import GuessingSettingsForm from './GuessingSettingsForm';
+import ChatBotLog from '../chat-bot-logs/ChatBotLog';
+import ChannelSelect from '../common/ChannelSelect';
+import Icon from '../common/Icon';
+import ToggleSwitch from '../common/ToggleSwitch';
+
+const CHAT_CATEGORIES = [
+       'unclassified',
+       'hi',
+       'gl',
+       'gg',
+       'eyes',
+       'love',
+       'lol',
+       'yes',
+       'no',
+       'rage',
+       'sad',
+       'sweat',
+       'wtf',
+       'pog',
+       'hype',
+       'kappa',
+       'o7',
+       'question',
+       'thx',
+];
+
+const Controls = () => {
+       const [channel, setChannel] = React.useState(null);
+       const [chatText, setChatText] = React.useState('');
+       const [editCommand, setEditCommand] = React.useState('');
+       const [editCommandSettings, setEditCommandSettings] = React.useState({});
+       const [showCommandDialog, setShowCommandDialog] = React.useState(false);
+
+       const { t } = useTranslation();
+
+       const chat = React.useCallback(async (text, bot_nick) => {
+               try {
+                       await axios.post(`/api/channels/${channel.id}/chat`, {
+                               text,
+                               bot_nick,
+                       });
+                       toastr.success(t('twitchBot.chatSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.chatError'));
+               }
+       }, [channel, t]);
+
+       const randomChat = React.useCallback(async (category) => {
+               try {
+                       await axios.post(`/api/channels/${channel.id}/chat`, {
+                               bot_nick: 'horstiebot',
+                               category,
+                       });
+                       toastr.success(t('twitchBot.chatSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.chatError'));
+               }
+       }, [channel, t]);
+
+       const adlibChat = React.useCallback(async () => {
+               try {
+                       await axios.post(`/api/channels/${channel.id}/chat`, {
+                               bot_nick: 'horstiebot',
+                               adlib: true,
+                       });
+                       toastr.success(t('twitchBot.chatSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.chatError'));
+               }
+       }, [channel, t]);
+
+       const join = React.useCallback(async (bot_nick) => {
+               try {
+                       const rsp = await axios.post(`/api/channels/${channel.id}/join`, { bot_nick });
+                       setChannel(rsp.data);
+                       toastr.success(t('twitchBot.joinSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.joinError'));
+               }
+       }, [channel, t]);
+
+       const part = React.useCallback(async (bot_nick) => {
+               try {
+                       const rsp = await axios.post(`/api/channels/${channel.id}/part`, { bot_nick });
+                       setChannel(rsp.data);
+                       toastr.success(t('twitchBot.partSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.partError'));
+               }
+       }, [channel, t]);
+
+       const saveChatSettings = React.useCallback(async (values) => {
+               try {
+                       const rsp = await axios.post(`/api/channels/${channel.id}/chat-settings`, values);
+                       setChannel(rsp.data);
+                       toastr.success(t('twitchBot.saveSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.saveError'));
+               }
+       }, [channel, t]);
+
+       const onAddCommand = React.useCallback(() => {
+               setEditCommand('');
+               setEditCommandSettings({});
+               setShowCommandDialog(true);
+       }, [channel]);
+
+       const onEditCommand = React.useCallback((name, settings) => {
+               setEditCommand(name);
+               setEditCommandSettings(settings);
+               setShowCommandDialog(true);
+       }, [channel]);
+
+       const onRemoveCommand = React.useCallback(async (name) => {
+               try {
+                       const rsp = await axios.delete(`/api/channels/${channel.id}/commands/${name}`);
+                       setChannel(rsp.data);
+                       toastr.success(t('twitchBot.saveSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.saveError'));
+               }
+       }, [channel]);
+
+       const saveCommand = React.useCallback(async (values) => {
+               try {
+                       const rsp = await axios.put(
+                               `/api/channels/${channel.id}/commands/${values.name}`,
+                               values,
+                       );
+                       setChannel(rsp.data);
+                       setShowCommandDialog(false);
+                       setEditCommand('');
+                       setEditCommandSettings({});
+                       toastr.success(t('twitchBot.saveSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.saveError'));
+                       throw e;
+               }
+       }, [channel]);
+
+       const saveGuessingGame = React.useCallback(async (values) => {
+               try {
+                       const rsp = await axios.put(
+                               `/api/channels/${channel.id}/guessing-game/${values.name}`,
+                               values,
+                       );
+                       setChannel(rsp.data);
+                       toastr.success(t('twitchBot.saveSuccess'));
+               } catch (e) {
+                       toastr.error(t('twitchBot.saveError'));
+                       throw e;
+               }
+       }, [channel]);
+
+       return <>
+               <Row className="mb-4">
+                       <Form.Group as={Col} md={6}>
+                               <Form.Label>{t('twitchBot.channel')}</Form.Label>
+                               <Form.Control
+                                       as={ChannelSelect}
+                                       autoSelect
+                                       joinable
+                                       manageable
+                                       onChange={({ channel }) => { setChannel(channel); }}
+                                       value={channel ? channel.id : ''}
+                               />
+                       </Form.Group>
+                       {channel ? <>
+                               <Form.Group as={Col} md={3}>
+                                       <Form.Label>{t('twitchBot.joinApp')}</Form.Label>
+                                       <div>
+                                               <Form.Control
+                                                       as={ToggleSwitch}
+                                                       onChange={({ target: { value } }) => {
+                                                               if (value) {
+                                                                       join('localhorsttv');
+                                                               } else {
+                                                                       part('localhorsttv');
+                                                               }
+                                                       }}
+                                                       value={channel.join}
+                                               />
+                                       </div>
+                               </Form.Group>
+                               <Form.Group as={Col} md={3}>
+                                       <Form.Label>{t('twitchBot.joinChat')}</Form.Label>
+                                       <div>
+                                               <Form.Control
+                                                       as={ToggleSwitch}
+                                                       onChange={({ target: { value } }) => {
+                                                               if (value) {
+                                                                       join('horstiebot');
+                                                               } else {
+                                                                       part('horstiebot');
+                                                               }
+                                                       }}
+                                                       value={channel.chat}
+                                               />
+                                       </div>
+                               </Form.Group>
+                       </> : null}
+               </Row>
+               {channel ?
+                       <Row>
+                               <Col className="mt-5" md={6}>
+                                       <h3>{t('twitchBot.chat')}</h3>
+                                       <Form.Group>
+                                               <Form.Label>{t('twitchBot.chat')}</Form.Label>
+                                               <Form.Control
+                                                       as="textarea"
+                                                       onChange={({ target: { value } }) => {
+                                                               setChatText(value);
+                                                       }}
+                                                       value={chatText}
+                                               />
+                                               <div className="button-bar">
+                                                       <Button
+                                                               className="mt-2"
+                                                               disabled={!chatText || !channel.join}
+                                                               onClick={() => {
+                                                                       if (chatText) chat(chatText, 'localhorsttv');
+                                                               }}
+                                                               variant="twitch"
+                                                       >
+                                                               {t('twitchBot.sendApp')}
+                                                       </Button>
+                                                       <Button
+                                                               className="mt-2"
+                                                               disabled={!chatText || !channel.chat}
+                                                               onClick={() => {
+                                                                       if (chatText) chat(chatText, 'horstiebot');
+                                                               }}
+                                                               variant="twitch"
+                                                       >
+                                                               {t('twitchBot.sendChat')}
+                                                       </Button>
+                                               </div>
+                                       </Form.Group>
+                                       <h3 className="mt-3">{t('twitchBot.randomChat')}</h3>
+                                       <div className="button-bar">
+                                               {CHAT_CATEGORIES.map(category =>
+                                                       <Button
+                                                               key={category}
+                                                               onClick={() => { randomChat(category); }}
+                                                               variant="outline-secondary"
+                                                       >
+                                                               {t(`twitchBot.chatCategories.${category}`)}
+                                                       </Button>
+                                               )}
+                                       </div>
+                                       <div className="mt-3">
+                                               <Button
+                                                       onClick={() => { adlibChat(); }}
+                                                       title={t('twitchBot.adlibChatDesc')}
+                                                       variant="outline-secondary"
+                                               >
+                                                       {t('twitchBot.adlibChat')}
+                                               </Button>
+                                               <p className="text-muted">{t('twitchBot.adlibChatNote')}</p>
+                                       </div>
+                               </Col>
+                               <Col className="mt-5" md={6}>
+                                       <div className="d-flex justify-content-between">
+                                               <h3>{t('twitchBot.chatSettings')}</h3>
+                                               <div className="button-bar">
+                                                       <ChatBotLog id={channel.id} />
+                                               </div>
+                                       </div>
+                                       <ChatSettingsForm channel={channel} onSubmit={saveChatSettings} />
+                               </Col>
+                               <Col className="mt-5" md={12}>
+                                       <h3>{t('twitchBot.commands')}</h3>
+                                       <Commands
+                                               channel={channel}
+                                               onEditCommand={onEditCommand}
+                                               onRemoveCommand={onRemoveCommand}
+                                       />
+                                       <CommandDialog
+                                               name={editCommand}
+                                               onHide={() => {
+                                                       setShowCommandDialog(false);
+                                                       setEditCommand('');
+                                                       setEditCommandSettings({});
+                                               }}
+                                               onSubmit={saveCommand}
+                                               settings={editCommandSettings}
+                                               show={showCommandDialog}
+                                       />
+                                       <div>
+                                               <Button onClick={onAddCommand} variant="primary">
+                                                       {t('twitchBot.addCommand')}
+                                               </Button>
+                                       </div>
+                               </Col>
+                               <Col className="mt-5" md={12}>
+                                       <div className="d-flex align-items-end justify-content-between">
+                                               <h3>{t('twitchBot.guessingGame.settings')}</h3>
+                                               <div className="button-bar">
+                                                       {channel.access_key ?
+                                                               <Button
+                                                                       href={`/guessing-game/monitor/${channel.access_key}`}
+                                                                       target="_blank"
+                                                                       title={t('button.browserSource')}
+                                                                       variant="outline-secondary"
+                                                               >
+                                                                       <Icon.BROWSER_SOURCE title="" />
+                                                               </Button>
+                                                       : null}
+                                                       <Button
+                                                               onClick={() => {
+                                                                       window.open(
+                                                                               `/guessing-game/controls/${channel.id}`,
+                                                                               '',
+                                                                               'width=640,height=800,titlebar=0,menubar=0,toolbar=0',
+                                                                       );
+                                                               }}
+                                                               title={t('twitchBot.guessingGame.popoutControls')}
+                                                               variant="outline-secondary"
+                                                       >
+                                                               <Icon.OPEN title="" />
+                                                       </Button>
+                                               </div>
+                                       </div>
+                                       <GuessingSettingsForm
+                                               name="gtbk"
+                                               onSubmit={saveGuessingGame}
+                                               settings={channel.guessing_settings?.gtbk || {}}
+                                       />
+                               </Col>
+                       </Row>
+               :
+                       <Alert variant="info">
+                               {t('twitchBot.selectChannel')}
+                       </Alert>
+               }
+       </>;
+};
+
+export default Controls;
diff --git a/resources/js/components/twitch-bot/GuessingGameAutoTracking.js b/resources/js/components/twitch-bot/GuessingGameAutoTracking.js
deleted file mode 100644 (file)
index 451c597..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import Icon from '../common/Icon';
-import ToggleSwitch from '../common/ToggleSwitch';
-import {
-       compareGTBasementState,
-       countGTBasementState,
-       getGTBasementState,
-       IN_GAME_MODES,
-       INV_ADDR,
-       RAM_ADDR,
-       SRAM_ADDR,
-       WRAM_ADDR,
-} from '../../helpers/alttp-ram';
-import { useSNES } from '../../hooks/snes';
-
-const GT_TYPES = [
-       0x02, // all dungeons
-       0x03, // defeat ganon
-       0x04, // fast ganon (the default and used for defeat ganon for some reason)
-       0x07, // crystals & bosses
-       0x08, // bosses
-       0x09, // all dungeons, no aga 1
-       0x0B, // completionist
-];
-
-const GT_ENTRANCE_ID = 55;
-
-const GuessingGameAutoTracking = ({ onSolve, onStart, onStop }) => {
-       const [enabled, setEnabled] = React.useState(false);
-       const controls = React.useRef({
-               onSolve,
-               onStart,
-               onStop,
-       });
-
-       const [inGame, setInGame] = React.useState(false);
-       const [seedType, setSeedType] = React.useState(0);
-       const [gtCrystals, setGTCrystals] = React.useState(0);
-       const [ganonType, setGanonType] = React.useState(0);
-       const [freeItemMenu, setFreeItemMenu] = React.useState(0);
-       const [pyramidOpen, setPyramidOpen] = React.useState(false);
-
-       const [ownedCrystals, setOwnedCrystals] = React.useState(0);
-       const [lastEntrance, setLastEntrance] = React.useState(0);
-       const [hasEntered, setHasEntered] = React.useState(false);
-       const [basement, setBasement] = React.useState({
-               state: getGTBasementState(),
-               last: '',
-               count: 0,
-               torch: 0,
-       });
-       const [hasBigKey, setHasBigKey] = React.useState(false);
-
-       const {
-               disable: disableSNES,
-               enable: enableSNES,
-               openSettings,
-               sock,
-               status,
-       } = useSNES();
-       const { t } = useTranslation();
-
-       React.useEffect(() => {
-               controls.current = {
-                       onSolve,
-                       onStart,
-                       onStop,
-               };
-       }, [onSolve, onStart, onStop]);
-
-       const resetState = React.useCallback(() => {
-               setInGame(false);
-               setSeedType(0);
-               setGTCrystals(0);
-               setGanonType(0);
-               setFreeItemMenu(0);
-
-               setOwnedCrystals(0);
-               setLastEntrance(0);
-               setHasEntered(false);
-               setBasement({
-                       state: getGTBasementState(),
-                       last: '',
-                       count: 0,
-                       torch: 0,
-               });
-               setHasBigKey(false);
-       }, []);
-
-       const enable = React.useCallback(() => {
-               enableSNES();
-               setEnabled(true);
-       }, []);
-
-       const disable = React.useCallback(() => {
-               disableSNES();
-               setEnabled(false);
-               resetState();
-       }, []);
-
-       React.useEffect(() => {
-               const savedSettings = localStorage.getItem('guessingGame.settings');
-               if (savedSettings) {
-                       const settings = JSON.parse(savedSettings);
-                       if (settings.autoTrack) {
-                               enable();
-                       }
-               }
-       }, []);
-
-       const saveSettings = React.useCallback((newSettings) => {
-               const savedSettings = localStorage.getItem('guessingGame.settings');
-               const settings = savedSettings
-                       ? { ...JSON.parse(savedSettings), ...newSettings }
-                       : newSettings;
-               localStorage.setItem('guessingGame.settings', JSON.stringify(settings));
-       }, []);
-
-       const toggle = React.useCallback(() => {
-               if (enabled) {
-                       disable();
-                       saveSettings({ autoTrack: false });
-               } else {
-                       enable();
-                       saveSettings({ autoTrack: true });
-               }
-       }, [enabled]);
-
-       // game mode timer
-       React.useEffect(() => {
-               if (enabled && !status.error && status.connected && status.device) {
-                       const checkInGame = () => {
-                               sock.current.readWRAM(WRAM_ADDR.GAME_MODE, 1, (data) => {
-                                       setInGame(IN_GAME_MODES.includes(data[0]));
-                               });
-                       };
-                       checkInGame();
-                       const timer = setInterval(checkInGame, 5000);
-                       return () => {
-                               clearInterval(timer);
-                       };
-               } else {
-                       setInGame(false);
-               }
-       }, [enabled && !status.error && status.connected && status.device]);
-
-       // refresh static game information
-       React.useEffect(() => {
-               if (!inGame) return;
-               sock.current.readBytes(RAM_ADDR.SEED_TYPE, 1, (data) => {
-                       setSeedType(data[0]);
-               });
-               sock.current.readBytes(RAM_ADDR.GT_CRYSTALS, 1, (data) => {
-                       setGTCrystals(data[0]);
-               });
-               sock.current.readBytes(RAM_ADDR.GANON_TYPE, 1, (data) => {
-                       setGanonType(data[0]);
-               });
-               sock.current.readBytes(RAM_ADDR.FREE_ITEM_MENU, 1, (data) => {
-                       setFreeItemMenu(data[0]);
-               });
-               sock.current.readBytes(RAM_ADDR.INIT_SRAM + SRAM_ADDR.PYRAMID_SCREEN, 1, (data) => {
-                       setPyramidOpen(!!(data[0] & 0x20));
-               });
-       }, [inGame, sock]);
-
-       const applicable = React.useMemo(() => {
-               return !seedType &&
-                       gtCrystals &&
-                       GT_TYPES.includes(ganonType) &&
-                       !pyramidOpen &&
-                       !(freeItemMenu & 0x02);
-       }, [freeItemMenu, ganonType, gtCrystals, pyramidOpen, seedType]);
-
-       // update crystals information
-       React.useEffect(() => {
-               if (!applicable || !inGame || hasBigKey) return;
-               const updateCrystals = () => {
-                       const crAddress = WRAM_ADDR.SAVE_DATA + SRAM_ADDR.INV_START + INV_ADDR.CRYSTALS;
-                       sock.current.readWRAM(crAddress, 1, (data) => {
-                               let owned = 0;
-                               for (let i = 0; i < 7; ++i) {
-                                       if (data[0] & Math.pow(2, i)) {
-                                               ++owned;
-                                       }
-                               }
-                               setOwnedCrystals(owned);
-                       });
-               };
-               // increase frequency for the last
-               const timer = setInterval(updateCrystals, ownedCrystals === gtCrystals - 1 ? 1000 : 15000);
-               return () => {
-                       clearInterval(timer);
-               };
-       }, [applicable, gtCrystals, hasBigKey, inGame, ownedCrystals, sock]);
-
-       // start game once all required crystals have been acquired
-       React.useEffect(() => {
-               if (!applicable || hasBigKey || ownedCrystals !== gtCrystals || hasEntered) return;
-               controls.current.onStart();
-               const updateDungeon = () => {
-                       sock.current.readWRAM(WRAM_ADDR.CURRENT_DUNGEON, 2, (data) => {
-                               setLastEntrance(data[0] + (data[1] * 256));
-                       });
-               };
-               const timer = setInterval(updateDungeon, 1000);
-               return () => {
-                       clearInterval(timer);
-               };
-       }, [applicable, controls, gtCrystals, hasBigKey, hasEntered, ownedCrystals]);
-
-       // stop game when GT has been entered
-       React.useEffect(() => {
-               if (!applicable || hasBigKey || ownedCrystals !== gtCrystals) return;
-               if (lastEntrance === GT_ENTRANCE_ID) {
-                       controls.current.onStop();
-                       setHasEntered(true);
-               }
-       }, [applicable, controls, gtCrystals, hasBigKey, lastEntrance, ownedCrystals]);
-
-       // watch GT state
-       React.useEffect(() => {
-               if (!applicable || !hasEntered || hasBigKey) return;
-               const updateGTState = () => {
-                       const roomDataStart = WRAM_ADDR.SAVE_DATA + SRAM_ADDR.ROOM_DATA_START;
-                       const roomDataSize = SRAM_ADDR.ROOM_DATA_END - SRAM_ADDR.ROOM_DATA_START;
-                       sock.current.readWRAM(roomDataStart, roomDataSize, (data) => {
-                               const gtState = getGTBasementState(data);
-                               const gtCount = countGTBasementState(gtState);
-                               setBasement(old => {
-                                       const cmp = compareGTBasementState(old.state, gtState);
-                                       if (cmp) {
-                                               return {
-                                                       state: gtState,
-                                                       last: cmp,
-                                                       count: gtCount,
-                                                       torch: cmp === 'torchSeen' ? gtCount : old.torch,
-                                               };
-                                       }
-                                       return old;
-                               });
-                       });
-               };
-               const timer = setInterval(updateGTState, 500);
-               return () => {
-                       clearInterval(timer);
-               };
-       }, [applicable, hasBigKey, hasEntered]);
-
-       React.useEffect(() => {
-               if (!applicable) return;
-               if (hasBigKey) {
-                       const solution = basement.last === 'torch' ? basement.torch : basement.count;
-                       controls.current.onSolve(solution);
-               } else {
-                       const bkAddr = WRAM_ADDR.SAVE_DATA + SRAM_ADDR.INV_START + INV_ADDR.BIG_KEY;
-                       sock.current.readWRAM(bkAddr, 1, (data) => {
-                               setHasBigKey(!!(data[0] & 0x04));
-                       });
-               }
-       }, [applicable, basement, controls, hasBigKey]);
-
-       const statusMsg = React.useMemo(() => {
-               if (!enabled) {
-                       return 'disabled';
-               }
-               if (status.error) {
-                       return 'error';
-               }
-               if (!status.connected) {
-                       return 'disconnected';
-               }
-               if (!status.device) {
-                       return 'no-device';
-               }
-               if (!inGame) {
-                       return 'not-in-game';
-               }
-               if (!applicable) {
-                       return 'not-applicable';
-               }
-               return 'tracking';
-       }, [applicable, enabled, inGame, status]);
-
-       return <div>
-               {['disconnected', 'error', 'no-device'].includes(statusMsg) ?
-                       <Icon.WARNING
-                               className="me-2 text-warning"
-                               size="lg"
-                               title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device  })}
-                       />
-               : null}
-               {['not-applicable', 'not-in-game'].includes(statusMsg) ?
-                       <Icon.INFO
-                               className="me-2 text-info"
-                               size="lg"
-                               title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device  })}
-                       />
-               : null}
-               <Button
-                       className="me-2"
-                       onClick={openSettings}
-                       size="sm"
-                       title={t('snes.settings')}
-                       variant="outline-secondary"
-               >
-                       <Icon.SETTINGS title="" />
-               </Button>
-               <ToggleSwitch
-                       onChange={toggle}
-                       title={t('autoTracking.heading')}
-                       value={enabled}
-               />
-       </div>;
-};
-
-GuessingGameAutoTracking.propTypes = {
-       onSolve: PropTypes.func,
-       onStart: PropTypes.func,
-       onStop: PropTypes.func,
-};
-
-export default GuessingGameAutoTracking;
diff --git a/resources/js/components/twitch-bot/GuessingGameAutoTracking.jsx b/resources/js/components/twitch-bot/GuessingGameAutoTracking.jsx
new file mode 100644 (file)
index 0000000..451c597
--- /dev/null
@@ -0,0 +1,327 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../common/Icon';
+import ToggleSwitch from '../common/ToggleSwitch';
+import {
+       compareGTBasementState,
+       countGTBasementState,
+       getGTBasementState,
+       IN_GAME_MODES,
+       INV_ADDR,
+       RAM_ADDR,
+       SRAM_ADDR,
+       WRAM_ADDR,
+} from '../../helpers/alttp-ram';
+import { useSNES } from '../../hooks/snes';
+
+const GT_TYPES = [
+       0x02, // all dungeons
+       0x03, // defeat ganon
+       0x04, // fast ganon (the default and used for defeat ganon for some reason)
+       0x07, // crystals & bosses
+       0x08, // bosses
+       0x09, // all dungeons, no aga 1
+       0x0B, // completionist
+];
+
+const GT_ENTRANCE_ID = 55;
+
+const GuessingGameAutoTracking = ({ onSolve, onStart, onStop }) => {
+       const [enabled, setEnabled] = React.useState(false);
+       const controls = React.useRef({
+               onSolve,
+               onStart,
+               onStop,
+       });
+
+       const [inGame, setInGame] = React.useState(false);
+       const [seedType, setSeedType] = React.useState(0);
+       const [gtCrystals, setGTCrystals] = React.useState(0);
+       const [ganonType, setGanonType] = React.useState(0);
+       const [freeItemMenu, setFreeItemMenu] = React.useState(0);
+       const [pyramidOpen, setPyramidOpen] = React.useState(false);
+
+       const [ownedCrystals, setOwnedCrystals] = React.useState(0);
+       const [lastEntrance, setLastEntrance] = React.useState(0);
+       const [hasEntered, setHasEntered] = React.useState(false);
+       const [basement, setBasement] = React.useState({
+               state: getGTBasementState(),
+               last: '',
+               count: 0,
+               torch: 0,
+       });
+       const [hasBigKey, setHasBigKey] = React.useState(false);
+
+       const {
+               disable: disableSNES,
+               enable: enableSNES,
+               openSettings,
+               sock,
+               status,
+       } = useSNES();
+       const { t } = useTranslation();
+
+       React.useEffect(() => {
+               controls.current = {
+                       onSolve,
+                       onStart,
+                       onStop,
+               };
+       }, [onSolve, onStart, onStop]);
+
+       const resetState = React.useCallback(() => {
+               setInGame(false);
+               setSeedType(0);
+               setGTCrystals(0);
+               setGanonType(0);
+               setFreeItemMenu(0);
+
+               setOwnedCrystals(0);
+               setLastEntrance(0);
+               setHasEntered(false);
+               setBasement({
+                       state: getGTBasementState(),
+                       last: '',
+                       count: 0,
+                       torch: 0,
+               });
+               setHasBigKey(false);
+       }, []);
+
+       const enable = React.useCallback(() => {
+               enableSNES();
+               setEnabled(true);
+       }, []);
+
+       const disable = React.useCallback(() => {
+               disableSNES();
+               setEnabled(false);
+               resetState();
+       }, []);
+
+       React.useEffect(() => {
+               const savedSettings = localStorage.getItem('guessingGame.settings');
+               if (savedSettings) {
+                       const settings = JSON.parse(savedSettings);
+                       if (settings.autoTrack) {
+                               enable();
+                       }
+               }
+       }, []);
+
+       const saveSettings = React.useCallback((newSettings) => {
+               const savedSettings = localStorage.getItem('guessingGame.settings');
+               const settings = savedSettings
+                       ? { ...JSON.parse(savedSettings), ...newSettings }
+                       : newSettings;
+               localStorage.setItem('guessingGame.settings', JSON.stringify(settings));
+       }, []);
+
+       const toggle = React.useCallback(() => {
+               if (enabled) {
+                       disable();
+                       saveSettings({ autoTrack: false });
+               } else {
+                       enable();
+                       saveSettings({ autoTrack: true });
+               }
+       }, [enabled]);
+
+       // game mode timer
+       React.useEffect(() => {
+               if (enabled && !status.error && status.connected && status.device) {
+                       const checkInGame = () => {
+                               sock.current.readWRAM(WRAM_ADDR.GAME_MODE, 1, (data) => {
+                                       setInGame(IN_GAME_MODES.includes(data[0]));
+                               });
+                       };
+                       checkInGame();
+                       const timer = setInterval(checkInGame, 5000);
+                       return () => {
+                               clearInterval(timer);
+                       };
+               } else {
+                       setInGame(false);
+               }
+       }, [enabled && !status.error && status.connected && status.device]);
+
+       // refresh static game information
+       React.useEffect(() => {
+               if (!inGame) return;
+               sock.current.readBytes(RAM_ADDR.SEED_TYPE, 1, (data) => {
+                       setSeedType(data[0]);
+               });
+               sock.current.readBytes(RAM_ADDR.GT_CRYSTALS, 1, (data) => {
+                       setGTCrystals(data[0]);
+               });
+               sock.current.readBytes(RAM_ADDR.GANON_TYPE, 1, (data) => {
+                       setGanonType(data[0]);
+               });
+               sock.current.readBytes(RAM_ADDR.FREE_ITEM_MENU, 1, (data) => {
+                       setFreeItemMenu(data[0]);
+               });
+               sock.current.readBytes(RAM_ADDR.INIT_SRAM + SRAM_ADDR.PYRAMID_SCREEN, 1, (data) => {
+                       setPyramidOpen(!!(data[0] & 0x20));
+               });
+       }, [inGame, sock]);
+
+       const applicable = React.useMemo(() => {
+               return !seedType &&
+                       gtCrystals &&
+                       GT_TYPES.includes(ganonType) &&
+                       !pyramidOpen &&
+                       !(freeItemMenu & 0x02);
+       }, [freeItemMenu, ganonType, gtCrystals, pyramidOpen, seedType]);
+
+       // update crystals information
+       React.useEffect(() => {
+               if (!applicable || !inGame || hasBigKey) return;
+               const updateCrystals = () => {
+                       const crAddress = WRAM_ADDR.SAVE_DATA + SRAM_ADDR.INV_START + INV_ADDR.CRYSTALS;
+                       sock.current.readWRAM(crAddress, 1, (data) => {
+                               let owned = 0;
+                               for (let i = 0; i < 7; ++i) {
+                                       if (data[0] & Math.pow(2, i)) {
+                                               ++owned;
+                                       }
+                               }
+                               setOwnedCrystals(owned);
+                       });
+               };
+               // increase frequency for the last
+               const timer = setInterval(updateCrystals, ownedCrystals === gtCrystals - 1 ? 1000 : 15000);
+               return () => {
+                       clearInterval(timer);
+               };
+       }, [applicable, gtCrystals, hasBigKey, inGame, ownedCrystals, sock]);
+
+       // start game once all required crystals have been acquired
+       React.useEffect(() => {
+               if (!applicable || hasBigKey || ownedCrystals !== gtCrystals || hasEntered) return;
+               controls.current.onStart();
+               const updateDungeon = () => {
+                       sock.current.readWRAM(WRAM_ADDR.CURRENT_DUNGEON, 2, (data) => {
+                               setLastEntrance(data[0] + (data[1] * 256));
+                       });
+               };
+               const timer = setInterval(updateDungeon, 1000);
+               return () => {
+                       clearInterval(timer);
+               };
+       }, [applicable, controls, gtCrystals, hasBigKey, hasEntered, ownedCrystals]);
+
+       // stop game when GT has been entered
+       React.useEffect(() => {
+               if (!applicable || hasBigKey || ownedCrystals !== gtCrystals) return;
+               if (lastEntrance === GT_ENTRANCE_ID) {
+                       controls.current.onStop();
+                       setHasEntered(true);
+               }
+       }, [applicable, controls, gtCrystals, hasBigKey, lastEntrance, ownedCrystals]);
+
+       // watch GT state
+       React.useEffect(() => {
+               if (!applicable || !hasEntered || hasBigKey) return;
+               const updateGTState = () => {
+                       const roomDataStart = WRAM_ADDR.SAVE_DATA + SRAM_ADDR.ROOM_DATA_START;
+                       const roomDataSize = SRAM_ADDR.ROOM_DATA_END - SRAM_ADDR.ROOM_DATA_START;
+                       sock.current.readWRAM(roomDataStart, roomDataSize, (data) => {
+                               const gtState = getGTBasementState(data);
+                               const gtCount = countGTBasementState(gtState);
+                               setBasement(old => {
+                                       const cmp = compareGTBasementState(old.state, gtState);
+                                       if (cmp) {
+                                               return {
+                                                       state: gtState,
+                                                       last: cmp,
+                                                       count: gtCount,
+                                                       torch: cmp === 'torchSeen' ? gtCount : old.torch,
+                                               };
+                                       }
+                                       return old;
+                               });
+                       });
+               };
+               const timer = setInterval(updateGTState, 500);
+               return () => {
+                       clearInterval(timer);
+               };
+       }, [applicable, hasBigKey, hasEntered]);
+
+       React.useEffect(() => {
+               if (!applicable) return;
+               if (hasBigKey) {
+                       const solution = basement.last === 'torch' ? basement.torch : basement.count;
+                       controls.current.onSolve(solution);
+               } else {
+                       const bkAddr = WRAM_ADDR.SAVE_DATA + SRAM_ADDR.INV_START + INV_ADDR.BIG_KEY;
+                       sock.current.readWRAM(bkAddr, 1, (data) => {
+                               setHasBigKey(!!(data[0] & 0x04));
+                       });
+               }
+       }, [applicable, basement, controls, hasBigKey]);
+
+       const statusMsg = React.useMemo(() => {
+               if (!enabled) {
+                       return 'disabled';
+               }
+               if (status.error) {
+                       return 'error';
+               }
+               if (!status.connected) {
+                       return 'disconnected';
+               }
+               if (!status.device) {
+                       return 'no-device';
+               }
+               if (!inGame) {
+                       return 'not-in-game';
+               }
+               if (!applicable) {
+                       return 'not-applicable';
+               }
+               return 'tracking';
+       }, [applicable, enabled, inGame, status]);
+
+       return <div>
+               {['disconnected', 'error', 'no-device'].includes(statusMsg) ?
+                       <Icon.WARNING
+                               className="me-2 text-warning"
+                               size="lg"
+                               title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device  })}
+                       />
+               : null}
+               {['not-applicable', 'not-in-game'].includes(statusMsg) ?
+                       <Icon.INFO
+                               className="me-2 text-info"
+                               size="lg"
+                               title={t(`autoTracking.statusMsg.${statusMsg}`, { device: status.device  })}
+                       />
+               : null}
+               <Button
+                       className="me-2"
+                       onClick={openSettings}
+                       size="sm"
+                       title={t('snes.settings')}
+                       variant="outline-secondary"
+               >
+                       <Icon.SETTINGS title="" />
+               </Button>
+               <ToggleSwitch
+                       onChange={toggle}
+                       title={t('autoTracking.heading')}
+                       value={enabled}
+               />
+       </div>;
+};
+
+GuessingGameAutoTracking.propTypes = {
+       onSolve: PropTypes.func,
+       onStart: PropTypes.func,
+       onStop: PropTypes.func,
+};
+
+export default GuessingGameAutoTracking;
diff --git a/resources/js/components/twitch-bot/GuessingGameControls.js b/resources/js/components/twitch-bot/GuessingGameControls.js
deleted file mode 100644 (file)
index 50a3c3a..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import GuessingGameAutoTracking from './GuessingGameAutoTracking';
-import {
-       hasActiveGuessing,
-       isAcceptingGuesses,
-} from '../../helpers/Channel';
-
-const GuessingGameControls = ({
-       channel,
-       onCancel,
-       onSolve,
-       onStart,
-       onStop,
-}) => {
-       const { t } = useTranslation();
-
-       const solutions = [
-               1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
-               13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
-       ];
-
-       return <div>
-               <div className="d-flex align-items-center justify-content-between mt-3">
-                       <div className="button-bar">
-                               <Button
-                                       onClick={onStart}
-                                       variant={hasActiveGuessing(channel) ? 'success' : 'outline-success'}
-                               >
-                                       {t('button.start')}
-                               </Button>
-                               <Button
-                                       onClick={onStop}
-                                       variant={
-                                               hasActiveGuessing(channel) && isAcceptingGuesses(channel)
-                                               ? 'danger' : 'outline-danger'
-                                       }
-                               >
-                                       {t('button.stop')}
-                               </Button>
-                               <Button
-                                       className="ms-3"
-                                       onClick={onCancel}
-                                       variant={hasActiveGuessing(channel) ? 'secondary' : 'outline-secondary'}
-                               >
-                                       {t('button.cancel')}
-                               </Button>
-                       </div>
-                       <GuessingGameAutoTracking
-                               onSolve={onSolve}
-                               onStart={onStart}
-                               onStop={onStop}
-                       />
-               </div>
-               {hasActiveGuessing(channel) ?
-                       <div className="bkgg-buttons d-grid gap-3 my-3">
-                               {solutions.map(solution =>
-                                       <Button
-                                               key={solution}
-                                               onClick={() => onSolve(solution)}
-                                               size="lg"
-                                               variant="outline-secondary"
-                                       >
-                                               {solution}
-                                       </Button>
-                               )}
-                       </div>
-               : null}
-       </div>;
-};
-
-GuessingGameControls.propTypes = {
-       channel: PropTypes.shape({
-       }),
-       onCancel: PropTypes.func,
-       onSolve: PropTypes.func,
-       onStart: PropTypes.func,
-       onStop: PropTypes.func,
-};
-
-export default GuessingGameControls;
diff --git a/resources/js/components/twitch-bot/GuessingGameControls.jsx b/resources/js/components/twitch-bot/GuessingGameControls.jsx
new file mode 100644 (file)
index 0000000..50a3c3a
--- /dev/null
@@ -0,0 +1,84 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import GuessingGameAutoTracking from './GuessingGameAutoTracking';
+import {
+       hasActiveGuessing,
+       isAcceptingGuesses,
+} from '../../helpers/Channel';
+
+const GuessingGameControls = ({
+       channel,
+       onCancel,
+       onSolve,
+       onStart,
+       onStop,
+}) => {
+       const { t } = useTranslation();
+
+       const solutions = [
+               1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+               13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+       ];
+
+       return <div>
+               <div className="d-flex align-items-center justify-content-between mt-3">
+                       <div className="button-bar">
+                               <Button
+                                       onClick={onStart}
+                                       variant={hasActiveGuessing(channel) ? 'success' : 'outline-success'}
+                               >
+                                       {t('button.start')}
+                               </Button>
+                               <Button
+                                       onClick={onStop}
+                                       variant={
+                                               hasActiveGuessing(channel) && isAcceptingGuesses(channel)
+                                               ? 'danger' : 'outline-danger'
+                                       }
+                               >
+                                       {t('button.stop')}
+                               </Button>
+                               <Button
+                                       className="ms-3"
+                                       onClick={onCancel}
+                                       variant={hasActiveGuessing(channel) ? 'secondary' : 'outline-secondary'}
+                               >
+                                       {t('button.cancel')}
+                               </Button>
+                       </div>
+                       <GuessingGameAutoTracking
+                               onSolve={onSolve}
+                               onStart={onStart}
+                               onStop={onStop}
+                       />
+               </div>
+               {hasActiveGuessing(channel) ?
+                       <div className="bkgg-buttons d-grid gap-3 my-3">
+                               {solutions.map(solution =>
+                                       <Button
+                                               key={solution}
+                                               onClick={() => onSolve(solution)}
+                                               size="lg"
+                                               variant="outline-secondary"
+                                       >
+                                               {solution}
+                                       </Button>
+                               )}
+                       </div>
+               : null}
+       </div>;
+};
+
+GuessingGameControls.propTypes = {
+       channel: PropTypes.shape({
+       }),
+       onCancel: PropTypes.func,
+       onSolve: PropTypes.func,
+       onStart: PropTypes.func,
+       onStop: PropTypes.func,
+};
+
+export default GuessingGameControls;
diff --git a/resources/js/components/twitch-bot/GuessingGuess.js b/resources/js/components/twitch-bot/GuessingGuess.js
deleted file mode 100644 (file)
index 61997d3..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Col, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-const GuessingGuess = ({ guess }) => {
-       const { t } = useTranslation();
-
-       return <div className="my-2 p-2 border rounded">
-               <Row>
-                       <Col xs={6}>
-                               <div>{guess.uname}</div>
-                               <div className="text-muted">
-                                       {t('twitchBot.guessingGame.guessTimestamp', {
-                                               timestamp: new Date(guess.created_at),
-                                       })}
-                               </div>
-                       </Col>
-                       <Col xs={6}>
-                               <div className="fs-3 text-end">{guess.guess}</div>
-                       </Col>
-               </Row>
-       </div>;
-};
-
-GuessingGuess.propTypes = {
-       guess: PropTypes.shape({
-               created_at: PropTypes.string,
-               guess: PropTypes.string,
-               uname: PropTypes.string,
-       }),
-};
-
-export default GuessingGuess;
diff --git a/resources/js/components/twitch-bot/GuessingGuess.jsx b/resources/js/components/twitch-bot/GuessingGuess.jsx
new file mode 100644 (file)
index 0000000..61997d3
--- /dev/null
@@ -0,0 +1,34 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Col, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const GuessingGuess = ({ guess }) => {
+       const { t } = useTranslation();
+
+       return <div className="my-2 p-2 border rounded">
+               <Row>
+                       <Col xs={6}>
+                               <div>{guess.uname}</div>
+                               <div className="text-muted">
+                                       {t('twitchBot.guessingGame.guessTimestamp', {
+                                               timestamp: new Date(guess.created_at),
+                                       })}
+                               </div>
+                       </Col>
+                       <Col xs={6}>
+                               <div className="fs-3 text-end">{guess.guess}</div>
+                       </Col>
+               </Row>
+       </div>;
+};
+
+GuessingGuess.propTypes = {
+       guess: PropTypes.shape({
+               created_at: PropTypes.string,
+               guess: PropTypes.string,
+               uname: PropTypes.string,
+       }),
+};
+
+export default GuessingGuess;
diff --git a/resources/js/components/twitch-bot/GuessingSettingsForm.js b/resources/js/components/twitch-bot/GuessingSettingsForm.js
deleted file mode 100644 (file)
index a465e4e..0000000
+++ /dev/null
@@ -1,425 +0,0 @@
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import i18n from '../../i18n';
-import yup from '../../schema/yup';
-
-const GuessingSettingsForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       touched,
-       values,
-}) => {
-       const { t } = useTranslation();
-
-       return <Form noValidate onSubmit={handleSubmit}>
-               <Row>
-                       <Form.Group as={Col} controlId="gg.points_exact_first" md={6}>
-                               <Form.Label>{t('twitchBot.guessingGame.pointsExactFirst')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.points_exact_first && errors.points_exact_first)}
-                                       max="5"
-                                       min="1"
-                                       name="points_exact_first"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       step="1"
-                                       type="number"
-                                       value={values.points_exact_first || 0}
-                               />
-                               {touched.points_exact_first && errors.points_exact_first ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.points_exact_first)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group as={Col} controlId="gg.points_exact_other" md={6}>
-                               <Form.Label>{t('twitchBot.guessingGame.pointsExactOther')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.points_exact_other && errors.points_exact_other)}
-                                       max="5"
-                                       min="0"
-                                       name="points_exact_other"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       step="1"
-                                       type="number"
-                                       value={values.points_exact_other || 0}
-                               />
-                               {touched.points_exact_other && errors.points_exact_other ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.points_exact_other)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group as={Col} controlId="gg.points_close_first" md={6}>
-                               <Form.Label>{t('twitchBot.guessingGame.pointsCloseFirst')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.points_close_first && errors.points_close_first)}
-                                       max="5"
-                                       min="0"
-                                       name="points_close_first"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       step="0.5"
-                                       type="number"
-                                       value={values.points_close_first || 0}
-                               />
-                               {touched.points_close_first && errors.points_close_first ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.points_close_first)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group as={Col} controlId="gg.points_close_other" md={6}>
-                               <Form.Label>{t('twitchBot.guessingGame.pointsCloseOther')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.points_close_other && errors.points_close_other)}
-                                       max="5"
-                                       min="0"
-                                       name="points_close_other"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       step="0.5"
-                                       type="number"
-                                       value={values.points_close_other || 0}
-                               />
-                               {touched.points_close_other && errors.points_close_other ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.points_close_other)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group as={Col} controlId="gg.points_close_max" md={6}>
-                               <Form.Label>{t('twitchBot.guessingGame.pointsCloseMax')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.points_close_max && errors.points_close_max)}
-                                       min="0"
-                                       name="points_close_max"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       step="1"
-                                       type="number"
-                                       value={values.points_close_max || 0}
-                               />
-                               {touched.points_close_max && errors.points_close_max ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.points_close_max)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-                       <Form.Group as={Col} controlId="gg.leaderboard_type" md={6}>
-                               <Form.Label>{t('twitchBot.guessingGame.leaderboardType')}</Form.Label>
-                               <Form.Select
-                                       isInvalid={!!(touched.leaderboard_type && errors.leaderboard_type)}
-                                       name="leaderboard_type"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       value={values.leaderboard_type || 'all'}
-                               >
-                                       {['all', 'year', '365', 'month', '30'].map(type =>
-                                               <option key={type} value={type}>
-                                                       {t(`twitchBot.guessingGame.leaderboardTypes.${type}`)}
-                                               </option>
-                                       )}
-                               </Form.Select>
-                               {touched.leaderboard_type && errors.leaderboard_type ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {t(errors.leaderboard_type)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-               <Form.Group controlId="gg.start_message">
-                       <Form.Label>{t('twitchBot.guessingGame.startMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.start_message && errors.start_message)}
-                               name="start_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.start_message || ''}
-                       />
-                       {touched.start_message && errors.start_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.start_message)}
-                               </Form.Control.Feedback>
-                       : null}
-               </Form.Group>
-               <Form.Group controlId="gg.stop_message">
-                       <Form.Label>{t('twitchBot.guessingGame.stopMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.stop_message && errors.stop_message)}
-                               name="stop_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.stop_message || ''}
-                       />
-                       {touched.stop_message && errors.stop_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.stop_message)}
-                               </Form.Control.Feedback>
-                       : null}
-               </Form.Group>
-               <Form.Group controlId="gg.winners_message">
-                       <Form.Label>{t('twitchBot.guessingGame.winnersMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.winners_message && errors.winners_message)}
-                               name="winners_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.winners_message || ''}
-                       />
-                       {touched.winners_message && errors.winners_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.winners_message)}
-                               </Form.Control.Feedback>
-                       :
-                               <Form.Text muted>
-                                       {t('twitchBot.guessingGame.winnersMessageHint')}
-                               </Form.Text>
-                       }
-               </Form.Group>
-               <Form.Group controlId="gg.close_winners_message">
-                       <Form.Label>{t('twitchBot.guessingGame.closeWinnersMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.close_winners_message && errors.close_winners_message)}
-                               name="close_winners_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.close_winners_message || ''}
-                       />
-                       {touched.close_winners_message && errors.close_winners_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.close_winners_message)}
-                               </Form.Control.Feedback>
-                       :
-                               <Form.Text muted>
-                                       {t('twitchBot.guessingGame.closeWinnersMessageHint')}
-                               </Form.Text>
-                       }
-               </Form.Group>
-               <Form.Group controlId="gg.no_winners_message">
-                       <Form.Label>{t('twitchBot.guessingGame.noWinnersMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.no_winners_message && errors.no_winners_message)}
-                               name="no_winners_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.no_winners_message || ''}
-                       />
-                       {touched.no_winners_message && errors.no_winners_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.no_winners_message)}
-                               </Form.Control.Feedback>
-                       : null}
-               </Form.Group>
-               <Form.Group controlId="gg.cancel_message">
-                       <Form.Label>{t('twitchBot.guessingGame.cancelMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.cancel_message && errors.cancel_message)}
-                               name="cancel_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.cancel_message || ''}
-                       />
-                       {touched.cancel_message && errors.cancel_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.cancel_message)}
-                               </Form.Control.Feedback>
-                       : null}
-               </Form.Group>
-               <Form.Group controlId="gg.invalid_solution_message">
-                       <Form.Label>{t('twitchBot.guessingGame.invalidSolutionMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.invalid_solution_message && errors.invalid_solution_message)}
-                               name="invalid_solution_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.invalid_solution_message || ''}
-                       />
-                       {touched.invalid_solution_message && errors.invalid_solution_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.invalid_solution_message)}
-                               </Form.Control.Feedback>
-                       : null}
-               </Form.Group>
-               <Form.Group controlId="gg.active_message">
-                       <Form.Label>{t('twitchBot.guessingGame.activeMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.active_message && errors.active_message)}
-                               name="active_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.active_message || ''}
-                       />
-                       {touched.active_message && errors.active_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.active_message)}
-                               </Form.Control.Feedback>
-                       : null}
-               </Form.Group>
-               <Form.Group controlId="gg.not_active_message">
-                       <Form.Label>{t('twitchBot.guessingGame.notActiveMessage')}</Form.Label>
-                       <Form.Control
-                               isInvalid={!!(touched.not_active_message && errors.not_active_message)}
-                               name="not_active_message"
-                               onBlur={handleBlur}
-                               onChange={handleChange}
-                               type="text"
-                               value={values.not_active_message || ''}
-                       />
-                       {touched.not_active_message && errors.not_active_message ?
-                               <Form.Control.Feedback type="invalid">
-                                       {t(errors.not_active_message)}
-                               </Form.Control.Feedback>
-                       : null}
-               </Form.Group>
-               <div className="button-bar mt-3">
-                       {onCancel ?
-                               <Button onClick={onCancel} variant="secondary">
-                                       {t('button.cancel')}
-                               </Button>
-                       : null}
-                       <Button type="submit" variant="primary">
-                               {t('button.save')}
-                       </Button>
-               </div>
-       </Form>;
-};
-
-GuessingSettingsForm.propTypes = {
-       errors: PropTypes.shape({
-               active_message: PropTypes.string,
-               cancel_message: PropTypes.string,
-               close_winners_message: PropTypes.string,
-               invalid_solution_message: PropTypes.string,
-               leaderboard_type: PropTypes.string,
-               name: PropTypes.string,
-               no_winners_message: PropTypes.string,
-               not_active_message: PropTypes.string,
-               points_close_first: PropTypes.string,
-               points_close_max: PropTypes.string,
-               points_close_other: PropTypes.string,
-               points_exact_first: PropTypes.string,
-               points_exact_other: PropTypes.string,
-               start_message: PropTypes.string,
-               stop_message: PropTypes.string,
-               winners_message: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       name: PropTypes.string,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               active_message: PropTypes.bool,
-               cancel_message: PropTypes.bool,
-               close_winners_message: PropTypes.bool,
-               invalid_solution_message: PropTypes.bool,
-               leaderboard_type: PropTypes.bool,
-               name: PropTypes.bool,
-               no_winners_message: PropTypes.bool,
-               not_active_message: PropTypes.bool,
-               points_close_first: PropTypes.bool,
-               points_close_max: PropTypes.bool,
-               points_close_other: PropTypes.bool,
-               points_exact_first: PropTypes.bool,
-               points_exact_other: PropTypes.bool,
-               start_message: PropTypes.bool,
-               stop_message: PropTypes.bool,
-               winners_message: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               active_message: PropTypes.string,
-               cancel_message: PropTypes.string,
-               close_winners_message: PropTypes.string,
-               invalid_solution_message: PropTypes.string,
-               leaderboard_type: PropTypes.string,
-               name: PropTypes.string,
-               no_winners_message: PropTypes.string,
-               not_active_message: PropTypes.string,
-               points_close_first: PropTypes.number,
-               points_close_max: PropTypes.number,
-               points_close_other: PropTypes.number,
-               points_exact_first: PropTypes.number,
-               points_exact_other: PropTypes.number,
-               start_message: PropTypes.string,
-               stop_message: PropTypes.string,
-               winners_message: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'GuessingSettingsForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { setErrors } = actions;
-               const { onSubmit } = actions.props;
-               try {
-                       await onSubmit(values);
-               } catch (e) {
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ name, settings }) => {
-               const getNumericValue = (s, n, d) => s && Object.prototype.hasOwnProperty.call(s, n)
-                       ? s[n] : d;
-               const getStringValue = (s, n, d) => s && Object.prototype.hasOwnProperty.call(s, n)
-                       ? s[n] : i18n.t(`twitchBot.guessingGame.default${d}`);
-               return {
-                       active_message: getStringValue(settings, 'active_message', 'ActiveMessage'),
-                       cancel_message: getStringValue(settings, 'cancel_message', 'CancelMessage'),
-                       close_winners_message:
-                               getStringValue(settings, 'close_winners_message', 'CloseWinnersMessage'),
-                       invalid_solution_message:
-                               getStringValue(settings, 'invalid_solution_message', 'InvalidSolutionMessage'),
-                       leaderboard_type: (settings && settings.leaderboard_type) || 'all',
-                       name: name || '',
-                       no_winners_message: getStringValue(settings, 'no_winners_message', 'NoWinnersMessage'),
-                       not_active_message: getStringValue(settings, 'not_active_message', 'NotActiveMessage'),
-                       points_close_first: getNumericValue(settings, 'points_close_first', 1),
-                       points_close_max: getNumericValue(settings, 'points_close_max', 3),
-                       points_close_other: getNumericValue(settings, 'points_close_other', 1),
-                       points_exact_first: getNumericValue(settings, 'points_exact_first', 1),
-                       points_exact_other: getNumericValue(settings, 'points_exact_other', 1),
-                       start_message: getStringValue(settings, 'start_message', 'StartMessage'),
-                       stop_message: getStringValue(settings, 'stop_message', 'StopMessage'),
-                       winners_message: getStringValue(settings, 'winners_message', 'WinnersMessage'),
-               };
-       },
-       validationSchema: yup.object().shape({
-               active_message: yup.string(),
-               cancel_message: yup.string(),
-               close_winners_message: yup.string(),
-               leaderboard_type: yup.string(),
-               invalid_solution_message: yup.string(),
-               name: yup.string().required(),
-               no_winners_message: yup.string(),
-               not_active_message: yup.string(),
-               points_close_first: yup.number(),
-               points_close_max: yup.number(),
-               points_close_other: yup.number(),
-               points_exact_first: yup.number(),
-               points_exact_other: yup.number(),
-               start_message: yup.string(),
-               stop_message: yup.string(),
-               winners_message: yup.string(),
-       }),
-})(GuessingSettingsForm);
diff --git a/resources/js/components/twitch-bot/GuessingSettingsForm.jsx b/resources/js/components/twitch-bot/GuessingSettingsForm.jsx
new file mode 100644 (file)
index 0000000..a465e4e
--- /dev/null
@@ -0,0 +1,425 @@
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import i18n from '../../i18n';
+import yup from '../../schema/yup';
+
+const GuessingSettingsForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       touched,
+       values,
+}) => {
+       const { t } = useTranslation();
+
+       return <Form noValidate onSubmit={handleSubmit}>
+               <Row>
+                       <Form.Group as={Col} controlId="gg.points_exact_first" md={6}>
+                               <Form.Label>{t('twitchBot.guessingGame.pointsExactFirst')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.points_exact_first && errors.points_exact_first)}
+                                       max="5"
+                                       min="1"
+                                       name="points_exact_first"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       step="1"
+                                       type="number"
+                                       value={values.points_exact_first || 0}
+                               />
+                               {touched.points_exact_first && errors.points_exact_first ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.points_exact_first)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group as={Col} controlId="gg.points_exact_other" md={6}>
+                               <Form.Label>{t('twitchBot.guessingGame.pointsExactOther')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.points_exact_other && errors.points_exact_other)}
+                                       max="5"
+                                       min="0"
+                                       name="points_exact_other"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       step="1"
+                                       type="number"
+                                       value={values.points_exact_other || 0}
+                               />
+                               {touched.points_exact_other && errors.points_exact_other ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.points_exact_other)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group as={Col} controlId="gg.points_close_first" md={6}>
+                               <Form.Label>{t('twitchBot.guessingGame.pointsCloseFirst')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.points_close_first && errors.points_close_first)}
+                                       max="5"
+                                       min="0"
+                                       name="points_close_first"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       step="0.5"
+                                       type="number"
+                                       value={values.points_close_first || 0}
+                               />
+                               {touched.points_close_first && errors.points_close_first ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.points_close_first)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group as={Col} controlId="gg.points_close_other" md={6}>
+                               <Form.Label>{t('twitchBot.guessingGame.pointsCloseOther')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.points_close_other && errors.points_close_other)}
+                                       max="5"
+                                       min="0"
+                                       name="points_close_other"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       step="0.5"
+                                       type="number"
+                                       value={values.points_close_other || 0}
+                               />
+                               {touched.points_close_other && errors.points_close_other ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.points_close_other)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group as={Col} controlId="gg.points_close_max" md={6}>
+                               <Form.Label>{t('twitchBot.guessingGame.pointsCloseMax')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.points_close_max && errors.points_close_max)}
+                                       min="0"
+                                       name="points_close_max"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       step="1"
+                                       type="number"
+                                       value={values.points_close_max || 0}
+                               />
+                               {touched.points_close_max && errors.points_close_max ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.points_close_max)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+                       <Form.Group as={Col} controlId="gg.leaderboard_type" md={6}>
+                               <Form.Label>{t('twitchBot.guessingGame.leaderboardType')}</Form.Label>
+                               <Form.Select
+                                       isInvalid={!!(touched.leaderboard_type && errors.leaderboard_type)}
+                                       name="leaderboard_type"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={values.leaderboard_type || 'all'}
+                               >
+                                       {['all', 'year', '365', 'month', '30'].map(type =>
+                                               <option key={type} value={type}>
+                                                       {t(`twitchBot.guessingGame.leaderboardTypes.${type}`)}
+                                               </option>
+                                       )}
+                               </Form.Select>
+                               {touched.leaderboard_type && errors.leaderboard_type ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.leaderboard_type)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+               <Form.Group controlId="gg.start_message">
+                       <Form.Label>{t('twitchBot.guessingGame.startMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.start_message && errors.start_message)}
+                               name="start_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.start_message || ''}
+                       />
+                       {touched.start_message && errors.start_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.start_message)}
+                               </Form.Control.Feedback>
+                       : null}
+               </Form.Group>
+               <Form.Group controlId="gg.stop_message">
+                       <Form.Label>{t('twitchBot.guessingGame.stopMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.stop_message && errors.stop_message)}
+                               name="stop_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.stop_message || ''}
+                       />
+                       {touched.stop_message && errors.stop_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.stop_message)}
+                               </Form.Control.Feedback>
+                       : null}
+               </Form.Group>
+               <Form.Group controlId="gg.winners_message">
+                       <Form.Label>{t('twitchBot.guessingGame.winnersMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.winners_message && errors.winners_message)}
+                               name="winners_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.winners_message || ''}
+                       />
+                       {touched.winners_message && errors.winners_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.winners_message)}
+                               </Form.Control.Feedback>
+                       :
+                               <Form.Text muted>
+                                       {t('twitchBot.guessingGame.winnersMessageHint')}
+                               </Form.Text>
+                       }
+               </Form.Group>
+               <Form.Group controlId="gg.close_winners_message">
+                       <Form.Label>{t('twitchBot.guessingGame.closeWinnersMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.close_winners_message && errors.close_winners_message)}
+                               name="close_winners_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.close_winners_message || ''}
+                       />
+                       {touched.close_winners_message && errors.close_winners_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.close_winners_message)}
+                               </Form.Control.Feedback>
+                       :
+                               <Form.Text muted>
+                                       {t('twitchBot.guessingGame.closeWinnersMessageHint')}
+                               </Form.Text>
+                       }
+               </Form.Group>
+               <Form.Group controlId="gg.no_winners_message">
+                       <Form.Label>{t('twitchBot.guessingGame.noWinnersMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.no_winners_message && errors.no_winners_message)}
+                               name="no_winners_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.no_winners_message || ''}
+                       />
+                       {touched.no_winners_message && errors.no_winners_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.no_winners_message)}
+                               </Form.Control.Feedback>
+                       : null}
+               </Form.Group>
+               <Form.Group controlId="gg.cancel_message">
+                       <Form.Label>{t('twitchBot.guessingGame.cancelMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.cancel_message && errors.cancel_message)}
+                               name="cancel_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.cancel_message || ''}
+                       />
+                       {touched.cancel_message && errors.cancel_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.cancel_message)}
+                               </Form.Control.Feedback>
+                       : null}
+               </Form.Group>
+               <Form.Group controlId="gg.invalid_solution_message">
+                       <Form.Label>{t('twitchBot.guessingGame.invalidSolutionMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.invalid_solution_message && errors.invalid_solution_message)}
+                               name="invalid_solution_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.invalid_solution_message || ''}
+                       />
+                       {touched.invalid_solution_message && errors.invalid_solution_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.invalid_solution_message)}
+                               </Form.Control.Feedback>
+                       : null}
+               </Form.Group>
+               <Form.Group controlId="gg.active_message">
+                       <Form.Label>{t('twitchBot.guessingGame.activeMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.active_message && errors.active_message)}
+                               name="active_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.active_message || ''}
+                       />
+                       {touched.active_message && errors.active_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.active_message)}
+                               </Form.Control.Feedback>
+                       : null}
+               </Form.Group>
+               <Form.Group controlId="gg.not_active_message">
+                       <Form.Label>{t('twitchBot.guessingGame.notActiveMessage')}</Form.Label>
+                       <Form.Control
+                               isInvalid={!!(touched.not_active_message && errors.not_active_message)}
+                               name="not_active_message"
+                               onBlur={handleBlur}
+                               onChange={handleChange}
+                               type="text"
+                               value={values.not_active_message || ''}
+                       />
+                       {touched.not_active_message && errors.not_active_message ?
+                               <Form.Control.Feedback type="invalid">
+                                       {t(errors.not_active_message)}
+                               </Form.Control.Feedback>
+                       : null}
+               </Form.Group>
+               <div className="button-bar mt-3">
+                       {onCancel ?
+                               <Button onClick={onCancel} variant="secondary">
+                                       {t('button.cancel')}
+                               </Button>
+                       : null}
+                       <Button type="submit" variant="primary">
+                               {t('button.save')}
+                       </Button>
+               </div>
+       </Form>;
+};
+
+GuessingSettingsForm.propTypes = {
+       errors: PropTypes.shape({
+               active_message: PropTypes.string,
+               cancel_message: PropTypes.string,
+               close_winners_message: PropTypes.string,
+               invalid_solution_message: PropTypes.string,
+               leaderboard_type: PropTypes.string,
+               name: PropTypes.string,
+               no_winners_message: PropTypes.string,
+               not_active_message: PropTypes.string,
+               points_close_first: PropTypes.string,
+               points_close_max: PropTypes.string,
+               points_close_other: PropTypes.string,
+               points_exact_first: PropTypes.string,
+               points_exact_other: PropTypes.string,
+               start_message: PropTypes.string,
+               stop_message: PropTypes.string,
+               winners_message: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       name: PropTypes.string,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               active_message: PropTypes.bool,
+               cancel_message: PropTypes.bool,
+               close_winners_message: PropTypes.bool,
+               invalid_solution_message: PropTypes.bool,
+               leaderboard_type: PropTypes.bool,
+               name: PropTypes.bool,
+               no_winners_message: PropTypes.bool,
+               not_active_message: PropTypes.bool,
+               points_close_first: PropTypes.bool,
+               points_close_max: PropTypes.bool,
+               points_close_other: PropTypes.bool,
+               points_exact_first: PropTypes.bool,
+               points_exact_other: PropTypes.bool,
+               start_message: PropTypes.bool,
+               stop_message: PropTypes.bool,
+               winners_message: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               active_message: PropTypes.string,
+               cancel_message: PropTypes.string,
+               close_winners_message: PropTypes.string,
+               invalid_solution_message: PropTypes.string,
+               leaderboard_type: PropTypes.string,
+               name: PropTypes.string,
+               no_winners_message: PropTypes.string,
+               not_active_message: PropTypes.string,
+               points_close_first: PropTypes.number,
+               points_close_max: PropTypes.number,
+               points_close_other: PropTypes.number,
+               points_exact_first: PropTypes.number,
+               points_exact_other: PropTypes.number,
+               start_message: PropTypes.string,
+               stop_message: PropTypes.string,
+               winners_message: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'GuessingSettingsForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { setErrors } = actions;
+               const { onSubmit } = actions.props;
+               try {
+                       await onSubmit(values);
+               } catch (e) {
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ name, settings }) => {
+               const getNumericValue = (s, n, d) => s && Object.prototype.hasOwnProperty.call(s, n)
+                       ? s[n] : d;
+               const getStringValue = (s, n, d) => s && Object.prototype.hasOwnProperty.call(s, n)
+                       ? s[n] : i18n.t(`twitchBot.guessingGame.default${d}`);
+               return {
+                       active_message: getStringValue(settings, 'active_message', 'ActiveMessage'),
+                       cancel_message: getStringValue(settings, 'cancel_message', 'CancelMessage'),
+                       close_winners_message:
+                               getStringValue(settings, 'close_winners_message', 'CloseWinnersMessage'),
+                       invalid_solution_message:
+                               getStringValue(settings, 'invalid_solution_message', 'InvalidSolutionMessage'),
+                       leaderboard_type: (settings && settings.leaderboard_type) || 'all',
+                       name: name || '',
+                       no_winners_message: getStringValue(settings, 'no_winners_message', 'NoWinnersMessage'),
+                       not_active_message: getStringValue(settings, 'not_active_message', 'NotActiveMessage'),
+                       points_close_first: getNumericValue(settings, 'points_close_first', 1),
+                       points_close_max: getNumericValue(settings, 'points_close_max', 3),
+                       points_close_other: getNumericValue(settings, 'points_close_other', 1),
+                       points_exact_first: getNumericValue(settings, 'points_exact_first', 1),
+                       points_exact_other: getNumericValue(settings, 'points_exact_other', 1),
+                       start_message: getStringValue(settings, 'start_message', 'StartMessage'),
+                       stop_message: getStringValue(settings, 'stop_message', 'StopMessage'),
+                       winners_message: getStringValue(settings, 'winners_message', 'WinnersMessage'),
+               };
+       },
+       validationSchema: yup.object().shape({
+               active_message: yup.string(),
+               cancel_message: yup.string(),
+               close_winners_message: yup.string(),
+               leaderboard_type: yup.string(),
+               invalid_solution_message: yup.string(),
+               name: yup.string().required(),
+               no_winners_message: yup.string(),
+               not_active_message: yup.string(),
+               points_close_first: yup.number(),
+               points_close_max: yup.number(),
+               points_close_other: yup.number(),
+               points_exact_first: yup.number(),
+               points_exact_other: yup.number(),
+               start_message: yup.string(),
+               stop_message: yup.string(),
+               winners_message: yup.string(),
+       }),
+})(GuessingSettingsForm);
diff --git a/resources/js/components/twitch-bot/GuessingWinner.js b/resources/js/components/twitch-bot/GuessingWinner.js
deleted file mode 100644 (file)
index 64ecc96..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Col, Row } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-const GuessingWinner = ({ winner }) => {
-       const { t } = useTranslation();
-
-       const classNames = ['guessing-game-winner', 'my-2', 'p-2', 'border', 'rounded'];
-       if (!winner.score) {
-               classNames.push('no-points');
-       }
-
-       return <div className={classNames.join(' ')}>
-               <Row>
-                       <Col xs={6}>
-                               <div>{winner.uname}</div>
-                               <div>{t(
-                                       'twitchBot.guessingGame.winnerScore',
-                                       { count: winner.score, score: winner.score },
-                               )}</div>
-                       </Col>
-                       <Col xs={6}>
-                               <div className="fs-3 text-end">{winner.guess}</div>
-                       </Col>
-               </Row>
-       </div>;
-};
-
-GuessingWinner.propTypes = {
-       winner: PropTypes.shape({
-               guess: PropTypes.string,
-               score: PropTypes.number,
-               uname: PropTypes.string,
-       }),
-};
-
-export default GuessingWinner;
diff --git a/resources/js/components/twitch-bot/GuessingWinner.jsx b/resources/js/components/twitch-bot/GuessingWinner.jsx
new file mode 100644 (file)
index 0000000..64ecc96
--- /dev/null
@@ -0,0 +1,38 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Col, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const GuessingWinner = ({ winner }) => {
+       const { t } = useTranslation();
+
+       const classNames = ['guessing-game-winner', 'my-2', 'p-2', 'border', 'rounded'];
+       if (!winner.score) {
+               classNames.push('no-points');
+       }
+
+       return <div className={classNames.join(' ')}>
+               <Row>
+                       <Col xs={6}>
+                               <div>{winner.uname}</div>
+                               <div>{t(
+                                       'twitchBot.guessingGame.winnerScore',
+                                       { count: winner.score, score: winner.score },
+                               )}</div>
+                       </Col>
+                       <Col xs={6}>
+                               <div className="fs-3 text-end">{winner.guess}</div>
+                       </Col>
+               </Row>
+       </div>;
+};
+
+GuessingWinner.propTypes = {
+       winner: PropTypes.shape({
+               guess: PropTypes.string,
+               score: PropTypes.number,
+               uname: PropTypes.string,
+       }),
+};
+
+export default GuessingWinner;
diff --git a/resources/js/components/users/Box.js b/resources/js/components/users/Box.js
deleted file mode 100644 (file)
index c0d011b..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import { useNavigate } from 'react-router-dom';
-
-import { getAvatarUrl, getUserName } from '../../helpers/User';
-import i18n from '../../i18n';
-
-const Box = ({ discriminator, noLink, user }) => {
-       const navigate = useNavigate();
-
-       if (!user) {
-               return <span>{i18n.t('general.anonymous')}</span>;
-       }
-
-       const content = <>
-               <img alt="" src={getAvatarUrl(user)} />
-               <span>{discriminator ? user.username : getUserName(user)}</span>
-               {discriminator && user.discriminator && user.discriminator !== '0' ?
-                       <span className="text-muted">
-                               {'#'}
-                               {user.discriminator}
-                       </span>
-               : null}
-       </>;
-
-       if (noLink) {
-               return <span className="user-box">{content}</span>;
-       }
-
-       return <Button
-               className="user-box"
-               onClick={() => navigate(`/users/${user.id}`)}
-               variant="link"
-       >
-               {content}
-       </Button>;
-};
-
-Box.propTypes = {
-       discriminator: PropTypes.bool,
-       noLink: PropTypes.bool,
-       user: PropTypes.shape({
-               discriminator: PropTypes.string,
-               id: PropTypes.string,
-               nickname: PropTypes.string,
-               username: PropTypes.string,
-       }),
-};
-
-export default withTranslation()(Box);
diff --git a/resources/js/components/users/Box.jsx b/resources/js/components/users/Box.jsx
new file mode 100644 (file)
index 0000000..864a4f8
--- /dev/null
@@ -0,0 +1,57 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import { useNavigate } from 'react-router-dom';
+
+import { getAvatarUrl, getUserName } from '../../helpers/User';
+import i18n from '../../i18n';
+
+const Box = ({ discriminator, noLink, user }) => {
+       const navigate = useNavigate();
+
+       if (!user) {
+               return <span>{i18n.t('general.anonymous')}</span>;
+       }
+
+       const content = <>
+               <img alt="" src={getAvatarUrl(user)} />
+               <span>{discriminator ? user.username : getUserName(user)}</span>
+               {discriminator && user.discriminator && user.discriminator !== '0' ?
+                       <span className="text-muted">
+                               {'#'}
+                               {user.discriminator}
+                       </span>
+               : null}
+       </>;
+
+       if (noLink) {
+               return <span className="user-box">{content}</span>;
+       }
+
+       return <Button
+               className="user-box"
+               href={`/users/${user.username}`}
+               onClick={(e) => {
+                       navigate(`/users/${user.username}`);
+                       e.preventDefault();
+                       e.stopPropagation();
+               }}
+               variant="link"
+       >
+               {content}
+       </Button>;
+};
+
+Box.propTypes = {
+       discriminator: PropTypes.bool,
+       noLink: PropTypes.bool,
+       user: PropTypes.shape({
+               discriminator: PropTypes.string,
+               id: PropTypes.string,
+               nickname: PropTypes.string,
+               username: PropTypes.string,
+       }),
+};
+
+export default withTranslation()(Box);
diff --git a/resources/js/components/users/EditNicknameButton.js b/resources/js/components/users/EditNicknameButton.js
deleted file mode 100644 (file)
index 3e39b3a..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import EditNicknameDialog from './EditNicknameDialog';
-import Icon from '../common/Icon';
-import { mayEditNickname } from '../../helpers/permissions';
-import { useUser } from '../../hooks/user';
-
-const EditNicknameButton = ({ user }) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       const { t } = useTranslation();
-       const { user: authUser } = useUser();
-
-       if (mayEditNickname(authUser, user)) {
-               return <>
-                       <EditNicknameDialog
-                               onHide={() => setShowDialog(false)}
-                               show={showDialog}
-                               user={user}
-                       />
-                       <Button
-                               onClick={() => setShowDialog(true)}
-                               title={t('button.edit')}
-                               variant="outline-secondary"
-                       >
-                               <Icon.EDIT title="" />
-                       </Button>
-               </>;
-       }
-       return null;
-};
-
-EditNicknameButton.propTypes = {
-       user: PropTypes.shape({
-       }),
-};
-
-export default EditNicknameButton;
diff --git a/resources/js/components/users/EditNicknameButton.jsx b/resources/js/components/users/EditNicknameButton.jsx
new file mode 100644 (file)
index 0000000..3e39b3a
--- /dev/null
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import EditNicknameDialog from './EditNicknameDialog';
+import Icon from '../common/Icon';
+import { mayEditNickname } from '../../helpers/permissions';
+import { useUser } from '../../hooks/user';
+
+const EditNicknameButton = ({ user }) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       const { t } = useTranslation();
+       const { user: authUser } = useUser();
+
+       if (mayEditNickname(authUser, user)) {
+               return <>
+                       <EditNicknameDialog
+                               onHide={() => setShowDialog(false)}
+                               show={showDialog}
+                               user={user}
+                       />
+                       <Button
+                               onClick={() => setShowDialog(true)}
+                               title={t('button.edit')}
+                               variant="outline-secondary"
+                       >
+                               <Icon.EDIT title="" />
+                       </Button>
+               </>;
+       }
+       return null;
+};
+
+EditNicknameButton.propTypes = {
+       user: PropTypes.shape({
+       }),
+};
+
+export default EditNicknameButton;
diff --git a/resources/js/components/users/EditNicknameDialog.js b/resources/js/components/users/EditNicknameDialog.js
deleted file mode 100644 (file)
index dbc9cbf..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import EditNicknameForm from './EditNicknameForm';
-import i18n from '../../i18n';
-
-const EditNicknameDialog = ({
-       onHide,
-       show,
-       user,
-}) =>
-<Modal className="edit-stream-link-dialog" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('users.editNickname')}
-               </Modal.Title>
-       </Modal.Header>
-       <EditNicknameForm
-               onCancel={onHide}
-               user={user}
-       />
-</Modal>;
-
-EditNicknameDialog.propTypes = {
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-       user: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(EditNicknameDialog);
diff --git a/resources/js/components/users/EditNicknameDialog.jsx b/resources/js/components/users/EditNicknameDialog.jsx
new file mode 100644 (file)
index 0000000..dbc9cbf
--- /dev/null
@@ -0,0 +1,33 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import EditNicknameForm from './EditNicknameForm';
+import i18n from '../../i18n';
+
+const EditNicknameDialog = ({
+       onHide,
+       show,
+       user,
+}) =>
+<Modal className="edit-stream-link-dialog" onHide={onHide} show={show}>
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t('users.editNickname')}
+               </Modal.Title>
+       </Modal.Header>
+       <EditNicknameForm
+               onCancel={onHide}
+               user={user}
+       />
+</Modal>;
+
+EditNicknameDialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+       user: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(EditNicknameDialog);
diff --git a/resources/js/components/users/EditNicknameForm.js b/resources/js/components/users/EditNicknameForm.js
deleted file mode 100644 (file)
index 56176f2..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-import axios from 'axios';
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import i18n from '../../i18n';
-import yup from '../../schema/yup';
-
-const EditStreamLinkForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       touched,
-       user,
-       values,
-}) =>
-<Form noValidate onSubmit={handleSubmit}>
-       <Modal.Body>
-               <Row>
-                       <Form.Group as={Col} controlId="user.nickname">
-                               <Form.Label>{i18n.t('users.nickname')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.nickname && errors.nickname)}
-                                       name="nickname"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       placeholder={user.username}
-                                       type="text"
-                                       value={values.nickname || ''}
-                               />
-                               {touched.nickname && errors.nickname ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {i18n.t(errors.nickname)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-       </Modal.Body>
-       <Modal.Footer>
-               {onCancel ?
-                       <Button onClick={onCancel} variant="secondary">
-                               {i18n.t('button.cancel')}
-                       </Button>
-               : null}
-               <Button type="submit" variant="primary">
-                       {i18n.t('button.save')}
-               </Button>
-       </Modal.Footer>
-</Form>;
-
-EditStreamLinkForm.propTypes = {
-       errors: PropTypes.shape({
-               nickname: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               nickname: PropTypes.bool,
-       }),
-       user: PropTypes.shape({
-               username: PropTypes.string,
-       }),
-       values: PropTypes.shape({
-               nickname: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'NicknameForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { user_id, nickname } = values;
-               const { setErrors } = actions;
-               const { onCancel } = actions.props;
-               try {
-                       await axios.post(`/api/users/${user_id}/setNickname`, {
-                               nickname,
-                       });
-                       toastr.success(i18n.t('users.setNicknameSuccess'));
-                       if (onCancel) {
-                               onCancel();
-                       }
-               } catch (e) {
-                       toastr.error(i18n.t('users.setNicknameError'));
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ user }) => ({
-               user_id: user.id,
-               nickname: user.nickname || '',
-       }),
-       validationSchema: yup.object().shape({
-               nickname: yup.string(),
-       }),
-})(withTranslation()(EditStreamLinkForm));
diff --git a/resources/js/components/users/EditNicknameForm.jsx b/resources/js/components/users/EditNicknameForm.jsx
new file mode 100644 (file)
index 0000000..56176f2
--- /dev/null
@@ -0,0 +1,105 @@
+import axios from 'axios';
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import i18n from '../../i18n';
+import yup from '../../schema/yup';
+
+const EditStreamLinkForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       touched,
+       user,
+       values,
+}) =>
+<Form noValidate onSubmit={handleSubmit}>
+       <Modal.Body>
+               <Row>
+                       <Form.Group as={Col} controlId="user.nickname">
+                               <Form.Label>{i18n.t('users.nickname')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.nickname && errors.nickname)}
+                                       name="nickname"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       placeholder={user.username}
+                                       type="text"
+                                       value={values.nickname || ''}
+                               />
+                               {touched.nickname && errors.nickname ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {i18n.t(errors.nickname)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+       </Modal.Body>
+       <Modal.Footer>
+               {onCancel ?
+                       <Button onClick={onCancel} variant="secondary">
+                               {i18n.t('button.cancel')}
+                       </Button>
+               : null}
+               <Button type="submit" variant="primary">
+                       {i18n.t('button.save')}
+               </Button>
+       </Modal.Footer>
+</Form>;
+
+EditStreamLinkForm.propTypes = {
+       errors: PropTypes.shape({
+               nickname: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               nickname: PropTypes.bool,
+       }),
+       user: PropTypes.shape({
+               username: PropTypes.string,
+       }),
+       values: PropTypes.shape({
+               nickname: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'NicknameForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { user_id, nickname } = values;
+               const { setErrors } = actions;
+               const { onCancel } = actions.props;
+               try {
+                       await axios.post(`/api/users/${user_id}/setNickname`, {
+                               nickname,
+                       });
+                       toastr.success(i18n.t('users.setNicknameSuccess'));
+                       if (onCancel) {
+                               onCancel();
+                       }
+               } catch (e) {
+                       toastr.error(i18n.t('users.setNicknameError'));
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ user }) => ({
+               user_id: user.id,
+               nickname: user.nickname || '',
+       }),
+       validationSchema: yup.object().shape({
+               nickname: yup.string(),
+       }),
+})(withTranslation()(EditStreamLinkForm));
diff --git a/resources/js/components/users/EditStreamLinkButton.js b/resources/js/components/users/EditStreamLinkButton.js
deleted file mode 100644 (file)
index 50fffdb..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-import PropTypes from 'prop-types';
-import React, { useState } from 'react';
-import { Button } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import EditStreamLinkDialog from './EditStreamLinkDialog';
-import Icon from '../common/Icon';
-import { mayEditStreamLink } from '../../helpers/permissions';
-import { useUser } from '../../hooks/user';
-
-const EditStreamLinkButton = ({ user }) => {
-       const [showDialog, setShowDialog] = useState(false);
-
-       const { t } = useTranslation();
-       const { user: authUser } = useUser();
-
-       if (mayEditStreamLink(authUser, user)) {
-               return <>
-                       <EditStreamLinkDialog
-                               onHide={() => setShowDialog(false)}
-                               show={showDialog}
-                               user={user}
-                       />
-                       <Button
-                               onClick={() => setShowDialog(true)}
-                               title={t('button.edit')}
-                               variant="outline-secondary"
-                       >
-                               <Icon.EDIT title="" />
-                       </Button>
-               </>;
-       }
-       return null;
-};
-
-EditStreamLinkButton.propTypes = {
-       user: PropTypes.shape({
-       }),
-};
-
-export default EditStreamLinkButton;
diff --git a/resources/js/components/users/EditStreamLinkButton.jsx b/resources/js/components/users/EditStreamLinkButton.jsx
new file mode 100644 (file)
index 0000000..50fffdb
--- /dev/null
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import React, { useState } from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import EditStreamLinkDialog from './EditStreamLinkDialog';
+import Icon from '../common/Icon';
+import { mayEditStreamLink } from '../../helpers/permissions';
+import { useUser } from '../../hooks/user';
+
+const EditStreamLinkButton = ({ user }) => {
+       const [showDialog, setShowDialog] = useState(false);
+
+       const { t } = useTranslation();
+       const { user: authUser } = useUser();
+
+       if (mayEditStreamLink(authUser, user)) {
+               return <>
+                       <EditStreamLinkDialog
+                               onHide={() => setShowDialog(false)}
+                               show={showDialog}
+                               user={user}
+                       />
+                       <Button
+                               onClick={() => setShowDialog(true)}
+                               title={t('button.edit')}
+                               variant="outline-secondary"
+                       >
+                               <Icon.EDIT title="" />
+                       </Button>
+               </>;
+       }
+       return null;
+};
+
+EditStreamLinkButton.propTypes = {
+       user: PropTypes.shape({
+       }),
+};
+
+export default EditStreamLinkButton;
diff --git a/resources/js/components/users/EditStreamLinkDialog.js b/resources/js/components/users/EditStreamLinkDialog.js
deleted file mode 100644 (file)
index 34db12e..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Modal } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import EditStreamLinkForm from './EditStreamLinkForm';
-import i18n from '../../i18n';
-
-const EditStreamLinkDialog = ({
-       onHide,
-       show,
-       user,
-}) =>
-<Modal className="edit-stream-link-dialog" onHide={onHide} show={show}>
-       <Modal.Header closeButton>
-               <Modal.Title>
-                       {i18n.t('users.editStreamLink')}
-               </Modal.Title>
-       </Modal.Header>
-       <EditStreamLinkForm
-               onCancel={onHide}
-               user={user}
-       />
-</Modal>;
-
-EditStreamLinkDialog.propTypes = {
-       onHide: PropTypes.func,
-       show: PropTypes.bool,
-       user: PropTypes.shape({
-       }),
-};
-
-export default withTranslation()(EditStreamLinkDialog);
diff --git a/resources/js/components/users/EditStreamLinkDialog.jsx b/resources/js/components/users/EditStreamLinkDialog.jsx
new file mode 100644 (file)
index 0000000..34db12e
--- /dev/null
@@ -0,0 +1,33 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Modal } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+
+import EditStreamLinkForm from './EditStreamLinkForm';
+import i18n from '../../i18n';
+
+const EditStreamLinkDialog = ({
+       onHide,
+       show,
+       user,
+}) =>
+<Modal className="edit-stream-link-dialog" onHide={onHide} show={show}>
+       <Modal.Header closeButton>
+               <Modal.Title>
+                       {i18n.t('users.editStreamLink')}
+               </Modal.Title>
+       </Modal.Header>
+       <EditStreamLinkForm
+               onCancel={onHide}
+               user={user}
+       />
+</Modal>;
+
+EditStreamLinkDialog.propTypes = {
+       onHide: PropTypes.func,
+       show: PropTypes.bool,
+       user: PropTypes.shape({
+       }),
+};
+
+export default withTranslation()(EditStreamLinkDialog);
diff --git a/resources/js/components/users/EditStreamLinkForm.js b/resources/js/components/users/EditStreamLinkForm.js
deleted file mode 100644 (file)
index 0bc60a5..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-import axios from 'axios';
-import { withFormik } from 'formik';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
-import i18n from '../../i18n';
-import yup from '../../schema/yup';
-
-const EditStreamLinkForm = ({
-       errors,
-       handleBlur,
-       handleChange,
-       handleSubmit,
-       onCancel,
-       touched,
-       values,
-}) =>
-<Form noValidate onSubmit={handleSubmit}>
-       <Modal.Body>
-               <Row>
-                       <Form.Group as={Col} controlId="user.stream_link">
-                               <Form.Label>{i18n.t('users.streamLink')}</Form.Label>
-                               <Form.Control
-                                       isInvalid={!!(touched.stream_link && errors.stream_link)}
-                                       name="stream_link"
-                                       onBlur={handleBlur}
-                                       onChange={handleChange}
-                                       placeholder="https://www.twitch.tv/fgfm"
-                                       type="text"
-                                       value={values.stream_link || ''}
-                               />
-                               {touched.stream_link && errors.stream_link ?
-                                       <Form.Control.Feedback type="invalid">
-                                               {i18n.t(errors.stream_link)}
-                                       </Form.Control.Feedback>
-                               : null}
-                       </Form.Group>
-               </Row>
-       </Modal.Body>
-       <Modal.Footer>
-               {onCancel ?
-                       <Button onClick={onCancel} variant="secondary">
-                               {i18n.t('button.cancel')}
-                       </Button>
-               : null}
-               <Button type="submit" variant="primary">
-                       {i18n.t('button.save')}
-               </Button>
-       </Modal.Footer>
-</Form>;
-
-EditStreamLinkForm.propTypes = {
-       errors: PropTypes.shape({
-               stream_link: PropTypes.string,
-       }),
-       handleBlur: PropTypes.func,
-       handleChange: PropTypes.func,
-       handleSubmit: PropTypes.func,
-       onCancel: PropTypes.func,
-       touched: PropTypes.shape({
-               stream_link: PropTypes.bool,
-       }),
-       values: PropTypes.shape({
-               stream_link: PropTypes.string,
-       }),
-};
-
-export default withFormik({
-       displayName: 'StreamLinkForm',
-       enableReinitialize: true,
-       handleSubmit: async (values, actions) => {
-               const { user_id, stream_link } = values;
-               const { setErrors } = actions;
-               const { onCancel } = actions.props;
-               try {
-                       await axios.post(`/api/users/${user_id}/setStreamLink`, {
-                               stream_link,
-                       });
-                       toastr.success(i18n.t('users.setStreamLinkSuccess'));
-                       if (onCancel) {
-                               onCancel();
-                       }
-               } catch (e) {
-                       toastr.error(i18n.t('users.setStreamLinkError'));
-                       if (e.response && e.response.data && e.response.data.errors) {
-                               setErrors(laravelErrorsToFormik(e.response.data.errors));
-                       }
-               }
-       },
-       mapPropsToValues: ({ user }) => ({
-               user_id: user.id,
-               stream_link: user.stream_link || '',
-       }),
-       validationSchema: yup.object().shape({
-               stream_link: yup.string().required().url(),
-       }),
-})(withTranslation()(EditStreamLinkForm));
diff --git a/resources/js/components/users/EditStreamLinkForm.jsx b/resources/js/components/users/EditStreamLinkForm.jsx
new file mode 100644 (file)
index 0000000..0bc60a5
--- /dev/null
@@ -0,0 +1,101 @@
+import axios from 'axios';
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import i18n from '../../i18n';
+import yup from '../../schema/yup';
+
+const EditStreamLinkForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       onCancel,
+       touched,
+       values,
+}) =>
+<Form noValidate onSubmit={handleSubmit}>
+       <Modal.Body>
+               <Row>
+                       <Form.Group as={Col} controlId="user.stream_link">
+                               <Form.Label>{i18n.t('users.streamLink')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.stream_link && errors.stream_link)}
+                                       name="stream_link"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       placeholder="https://www.twitch.tv/fgfm"
+                                       type="text"
+                                       value={values.stream_link || ''}
+                               />
+                               {touched.stream_link && errors.stream_link ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {i18n.t(errors.stream_link)}
+                                       </Form.Control.Feedback>
+                               : null}
+                       </Form.Group>
+               </Row>
+       </Modal.Body>
+       <Modal.Footer>
+               {onCancel ?
+                       <Button onClick={onCancel} variant="secondary">
+                               {i18n.t('button.cancel')}
+                       </Button>
+               : null}
+               <Button type="submit" variant="primary">
+                       {i18n.t('button.save')}
+               </Button>
+       </Modal.Footer>
+</Form>;
+
+EditStreamLinkForm.propTypes = {
+       errors: PropTypes.shape({
+               stream_link: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       onCancel: PropTypes.func,
+       touched: PropTypes.shape({
+               stream_link: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               stream_link: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'StreamLinkForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { user_id, stream_link } = values;
+               const { setErrors } = actions;
+               const { onCancel } = actions.props;
+               try {
+                       await axios.post(`/api/users/${user_id}/setStreamLink`, {
+                               stream_link,
+                       });
+                       toastr.success(i18n.t('users.setStreamLinkSuccess'));
+                       if (onCancel) {
+                               onCancel();
+                       }
+               } catch (e) {
+                       toastr.error(i18n.t('users.setStreamLinkError'));
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ user }) => ({
+               user_id: user.id,
+               stream_link: user.stream_link || '',
+       }),
+       validationSchema: yup.object().shape({
+               stream_link: yup.string().required().url(),
+       }),
+})(withTranslation()(EditStreamLinkForm));
diff --git a/resources/js/components/users/Participation.js b/resources/js/components/users/Participation.js
deleted file mode 100644 (file)
index 9b7228e..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Button, Table } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-import { useNavigate } from 'react-router-dom';
-
-import Icon from '../common/Icon';
-import { isRunner } from '../../helpers/Participant';
-import i18n from '../../i18n';
-
-const getIcon = participant => {
-       if (!isRunner(participant)) {
-               return '—';
-       }
-       if (participant.placement === 1) {
-               return <Icon.FIRST_PLACE className="text-gold" size="lg" />;
-       }
-       if (participant.placement === 2) {
-               return <Icon.SECOND_PLACE className="text-silver" size="lg" />;
-       }
-       if (participant.placement === 3) {
-               return <Icon.THIRD_PLACE className="text-bronze" size="lg" />;
-       }
-       return participant.placement;
-};
-
-const Participation = ({ user }) => {
-       const navigate = useNavigate();
-
-       if (!user || !user.participation || !user.participation.length) {
-               return <Alert variant="info">
-                       {i18n.t('users.participationEmpty')}
-               </Alert>;
-       }
-       return <Table className="participation align-middle">
-               <thead>
-                       <tr>
-                               <th>{i18n.t('participants.tournament')}</th>
-                               <th>{i18n.t('participants.placement')}</th>
-                               <th>{i18n.t('participants.roles')}</th>
-                       </tr>
-               </thead>
-               <tbody>
-               {user.participation.map(p => <tr key={p.id}>
-                       <td>
-                               <Button
-                                       onClick={() => navigate(`/tournaments/${p.tournament_id}`)}
-                                       variant="link"
-                               >
-                                       {p.tournament.title}
-                               </Button>
-                       </td>
-                       <td>
-                               {getIcon(p)}
-                       {!p.tournament.locked && isRunner(p) ?
-                               <span title={i18n.t('participants.placementSubjectToChange')}> *</span>
-                       : null}
-                       {p.tournament.no_record ?
-                               <span title={i18n.t('tournaments.noRecord')}> †</span>
-                       : null}
-                       </td>
-                       <td>
-                               {p.roles ? p.roles.map((role, index) =>
-                                       <span key={role}>
-                                               {index === 0 ? '' : ', '}
-                                               {i18n.t(`participants.roleNames.${role}`)}
-                                       </span>
-                               ) : null}
-                       </td>
-               </tr>)}
-               </tbody>
-       </Table>;
-};
-
-Participation.propTypes = {
-       user: PropTypes.shape({
-               participation: PropTypes.arrayOf(PropTypes.shape({
-                       id: PropTypes.number,
-               })),
-       }),
-};
-
-export default withTranslation()(Participation);
diff --git a/resources/js/components/users/Participation.jsx b/resources/js/components/users/Participation.jsx
new file mode 100644 (file)
index 0000000..9b7228e
--- /dev/null
@@ -0,0 +1,83 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, Table } from 'react-bootstrap';
+import { withTranslation } from 'react-i18next';
+import { useNavigate } from 'react-router-dom';
+
+import Icon from '../common/Icon';
+import { isRunner } from '../../helpers/Participant';
+import i18n from '../../i18n';
+
+const getIcon = participant => {
+       if (!isRunner(participant)) {
+               return '—';
+       }
+       if (participant.placement === 1) {
+               return <Icon.FIRST_PLACE className="text-gold" size="lg" />;
+       }
+       if (participant.placement === 2) {
+               return <Icon.SECOND_PLACE className="text-silver" size="lg" />;
+       }
+       if (participant.placement === 3) {
+               return <Icon.THIRD_PLACE className="text-bronze" size="lg" />;
+       }
+       return participant.placement;
+};
+
+const Participation = ({ user }) => {
+       const navigate = useNavigate();
+
+       if (!user || !user.participation || !user.participation.length) {
+               return <Alert variant="info">
+                       {i18n.t('users.participationEmpty')}
+               </Alert>;
+       }
+       return <Table className="participation align-middle">
+               <thead>
+                       <tr>
+                               <th>{i18n.t('participants.tournament')}</th>
+                               <th>{i18n.t('participants.placement')}</th>
+                               <th>{i18n.t('participants.roles')}</th>
+                       </tr>
+               </thead>
+               <tbody>
+               {user.participation.map(p => <tr key={p.id}>
+                       <td>
+                               <Button
+                                       onClick={() => navigate(`/tournaments/${p.tournament_id}`)}
+                                       variant="link"
+                               >
+                                       {p.tournament.title}
+                               </Button>
+                       </td>
+                       <td>
+                               {getIcon(p)}
+                       {!p.tournament.locked && isRunner(p) ?
+                               <span title={i18n.t('participants.placementSubjectToChange')}> *</span>
+                       : null}
+                       {p.tournament.no_record ?
+                               <span title={i18n.t('tournaments.noRecord')}> †</span>
+                       : null}
+                       </td>
+                       <td>
+                               {p.roles ? p.roles.map((role, index) =>
+                                       <span key={role}>
+                                               {index === 0 ? '' : ', '}
+                                               {i18n.t(`participants.roleNames.${role}`)}
+                                       </span>
+                               ) : null}
+                       </td>
+               </tr>)}
+               </tbody>
+       </Table>;
+};
+
+Participation.propTypes = {
+       user: PropTypes.shape({
+               participation: PropTypes.arrayOf(PropTypes.shape({
+                       id: PropTypes.number,
+               })),
+       }),
+};
+
+export default withTranslation()(Participation);
diff --git a/resources/js/components/users/Profile.js b/resources/js/components/users/Profile.js
deleted file mode 100644 (file)
index b4c4060..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Alert, Button, Col, Container, Row } from 'react-bootstrap';
-import { withTranslation } from 'react-i18next';
-
-import Box from './Box';
-import Records from './Records';
-import EditNicknameButton from './EditNicknameButton';
-import EditStreamLinkButton from './EditStreamLinkButton';
-import Participation from './Participation';
-import Icon from '../common/Icon';
-import i18n from '../../i18n';
-
-const Profile = ({ user }) => <Container>
-       <h1>
-               {user.nickname || user.username}
-               {' '}
-               <EditNicknameButton user={user} />
-       </h1>
-       {user.random_quote && user.random_quote.comment ?
-               <Alert className="quote-alert" variant="dark">
-                       <blockquote className="blockquote mb-0">
-                               {user.random_quote.comment}
-                       </blockquote>
-               </Alert>
-       : null}
-       <Row>
-               <Col md={6} className="mb-5">
-                       <h2>{i18n.t('users.discordTag')}</h2>
-                       <Box discriminator user={user} />
-               </Col>
-               <Col md={6} className="mb-5">
-                       <h2>{i18n.t('users.streamLink')}</h2>
-                       <p>
-                               {user.stream_link ?
-                                       <Button
-                                               href={user.stream_link}
-                                               target="_blank"
-                                               variant="outline-twitch"
-                                       >
-                                               <Icon.STREAM />
-                                               {' '}
-                                               {user.stream_link}
-                                       </Button>
-                               :
-                                       i18n.t('users.noStream')
-                               }
-                               {' '}
-                               <EditStreamLinkButton user={user} />
-                       </p>
-               </Col>
-               <Col md={6} className="mb-5">
-                       <h2>{i18n.t('users.tournamentRecords')}</h2>
-                       <Records
-                               first={user.tournament_first_count}
-                               second={user.tournament_second_count}
-                               third={user.tournament_third_count}
-                       />
-               </Col>
-               <Col md={6} className="mb-5">
-                       <h2>{i18n.t('users.roundRecords')}</h2>
-                       <Records
-                               first={user.round_first_count}
-                               second={user.round_second_count}
-                               third={user.round_third_count}
-                       />
-               </Col>
-               <Col md={12} className="mb-5">
-                       <h2>{i18n.t('users.tournaments')}</h2>
-                       <Participation user={user} />
-               </Col>
-       </Row>
-</Container>;
-
-Profile.propTypes = {
-       user: PropTypes.shape({
-               nickname: PropTypes.string,
-               participation: PropTypes.arrayOf(PropTypes.shape({
-               })),
-               random_quote: PropTypes.shape({
-                       comment: PropTypes.string,
-               }),
-               round_first_count: PropTypes.number,
-               round_second_count: PropTypes.number,
-               round_third_count: PropTypes.number,
-               stream_link: PropTypes.string,
-               tournament_first_count: PropTypes.number,
-               tournament_second_count: PropTypes.number,
-               tournament_third_count: PropTypes.number,
-               username: PropTypes.string,
-       }),
-};
-
-export default withTranslation()(Profile);
diff --git a/resources/js/components/users/Profile.jsx b/resources/js/components/users/Profile.jsx
new file mode 100644 (file)
index 0000000..0b9f940
--- /dev/null
@@ -0,0 +1,185 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Alert, Button, ButtonGroup, Col, Container, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import Box from './Box';
+import Records from './Records';
+import EditNicknameButton from './EditNicknameButton';
+import EditStreamLinkButton from './EditStreamLinkButton';
+import Participation from './Participation';
+import EpisodesList from '../episodes/List';
+import Icon from '../common/Icon';
+
+const Profile = ({ user }) => {
+       const [activeEpisodes, setActiveEpisodes] = React.useState('runner');
+
+       const { t } = useTranslation();
+
+       React.useEffect(() => {
+               if (!user.episodes_as_runner.length) {
+                       if (user.episodes_as_comms.length) {
+                               setActiveEpisodes('comms');
+                       } else if (user.episodes_as_tracker.length) {
+                               setActiveEpisodes('tracker');
+                       } else if (user.episodes_as_setup.length) {
+                               setActiveEpisodes('setup');
+                       }
+               } else {
+                       setActiveEpisodes('runner');
+               }
+       }, [user])
+
+       const participation = React.useMemo(() => {
+               let p = 0;
+               if (user.episodes_as_runner.length) ++p;
+               if (user.episodes_as_comms.length) ++p;
+               if (user.episodes_as_tracker.length) ++p;
+               if (user.episodes_as_setup.length) ++p;
+               return p;
+       }, [user]);
+
+
+       return <Container>
+               <h1>
+                       {user.nickname || user.username}
+                       {' '}
+                       <EditNicknameButton user={user} />
+               </h1>
+               {user.random_quote && user.random_quote.comment ?
+                       <Alert className="quote-alert" variant="dark">
+                               <blockquote className="blockquote mb-0">
+                                       {user.random_quote.comment}
+                               </blockquote>
+                       </Alert>
+               : null}
+               <Row>
+                       <Col md={6} className="mb-5">
+                               <h2>{t('users.discordTag')}</h2>
+                               <Box discriminator user={user} />
+                       </Col>
+                       <Col md={6} className="mb-5">
+                               <h2>{t('users.streamLink')}</h2>
+                               <p>
+                                       {user.stream_link ?
+                                               <Button
+                                                       href={user.stream_link}
+                                                       target="_blank"
+                                                       variant="outline-twitch"
+                                               >
+                                                       <Icon.STREAM />
+                                                       {' '}
+                                                       {user.stream_link}
+                                               </Button>
+                                       :
+                                               t('users.noStream')
+                                       }
+                                       {' '}
+                                       <EditStreamLinkButton user={user} />
+                               </p>
+                       </Col>
+                       <Col md={6} className="mb-5">
+                               <h2>{t('users.tournamentRecords')}</h2>
+                               <Records
+                                       first={user.tournament_first_count}
+                                       second={user.tournament_second_count}
+                                       third={user.tournament_third_count}
+                               />
+                       </Col>
+                       <Col md={6} className="mb-5">
+                               <h2>{t('users.roundRecords')}</h2>
+                               <Records
+                                       first={user.round_first_count}
+                                       second={user.round_second_count}
+                                       third={user.round_third_count}
+                               />
+                       </Col>
+                       <Col md={12} className="mb-5">
+                               <h2>{t('users.tournaments')}</h2>
+                               <Participation user={user} />
+                       </Col>
+                       {participation > 0 ?
+                               <Col md={12} className="mb-5">
+                                       <h2>{t('users.episodes')}</h2>
+                                       {participation > 1 ?
+                                               <ButtonGroup>
+                                                       {user.episodes_as_runner.length ?
+                                                               <Button
+                                                                       onClick={() => setActiveEpisodes('runner')}
+                                                                       variant={activeEpisodes === 'runner' ? 'secondary' : 'outline-secondary'}
+                                                               >
+                                                                       {t('button.asRunner')}
+                                                               </Button>
+                                                       : null}
+                                                       {user.episodes_as_comms.length ?
+                                                               <Button
+                                                                       onClick={() => setActiveEpisodes('comms')}
+                                                                       variant={activeEpisodes === 'comms' ? 'secondary' : 'outline-secondary'}
+                                                               >
+                                                                       {t('button.asComms')}
+                                                               </Button>
+                                                       : null}
+                                                       {user.episodes_as_tracker.length ?
+                                                               <Button
+                                                                       onClick={() => setActiveEpisodes('tracker')}
+                                                                       variant={activeEpisodes === 'tracker' ? 'secondary' : 'outline-secondary'}
+                                                               >
+                                                                       {t('button.asTracker')}
+                                                               </Button>
+                                                       : null}
+                                                       {user.episodes_as_setup.length ?
+                                                               <Button
+                                                                       onClick={() => setActiveEpisodes('setup')}
+                                                                       variant={activeEpisodes === 'setup' ? 'secondary' : 'outline-secondary'}
+                                                               >
+                                                                       {t('button.asSetup')}
+                                                               </Button>
+                                                       : null}
+                                               </ButtonGroup>
+                                       : null}
+                                       {activeEpisodes === 'runner' ?
+                                               <EpisodesList compact episodes={user.episodes_as_runner} />
+                                       : null}
+                                       {activeEpisodes === 'comms' ?
+                                               <EpisodesList compact episodes={user.episodes_as_comms} />
+                                       : null}
+                                       {activeEpisodes === 'tracker' ?
+                                               <EpisodesList compact episodes={user.episodes_as_tracker} />
+                                       : null}
+                                       {activeEpisodes === 'setup' ?
+                                               <EpisodesList compact episodes={user.episodes_as_setup} />
+                                       : null}
+                               </Col>
+                       : null}
+               </Row>
+       </Container>;
+};
+
+Profile.propTypes = {
+       user: PropTypes.shape({
+               episodes_as_comms: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               episodes_as_runner: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               episodes_as_setup: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               episodes_as_tracker: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               nickname: PropTypes.string,
+               participation: PropTypes.arrayOf(PropTypes.shape({
+               })),
+               random_quote: PropTypes.shape({
+                       comment: PropTypes.string,
+               }),
+               round_first_count: PropTypes.number,
+               round_second_count: PropTypes.number,
+               round_third_count: PropTypes.number,
+               stream_link: PropTypes.string,
+               tournament_first_count: PropTypes.number,
+               tournament_second_count: PropTypes.number,
+               tournament_third_count: PropTypes.number,
+               username: PropTypes.string,
+       }),
+};
+
+export default Profile;
diff --git a/resources/js/components/users/Records.js b/resources/js/components/users/Records.js
deleted file mode 100644 (file)
index 5b110fe..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Col, Row } from 'react-bootstrap';
-
-import Icon from '../common/Icon';
-
-const Records = ({
-       first,
-       second,
-       third,
-}) => <Row>
-       <Col>
-               <div className="record-box">
-                       <span className="icon">
-                               <Icon.FIRST_PLACE className="text-gold" />
-                       </span>
-                       <span className="count">
-                               {first}
-                       </span>
-               </div>
-       </Col>
-       <Col>
-               <div className="record-box">
-                       <span className="icon">
-                               <Icon.SECOND_PLACE className="text-silver" />
-                       </span>
-                       <span className="count">
-                               {second}
-                       </span>
-               </div>
-       </Col>
-       <Col>
-               <div className="record-box">
-                       <span className="icon">
-                               <Icon.THIRD_PLACE className="text-bronze" />
-                       </span>
-                       <span className="count">
-                               {third}
-                       </span>
-               </div>
-       </Col>
-</Row>;
-
-Records.propTypes = {
-       first: PropTypes.number,
-       second: PropTypes.number,
-       third: PropTypes.number,
-};
-
-export default Records;
diff --git a/resources/js/components/users/Records.jsx b/resources/js/components/users/Records.jsx
new file mode 100644 (file)
index 0000000..5b110fe
--- /dev/null
@@ -0,0 +1,50 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Col, Row } from 'react-bootstrap';
+
+import Icon from '../common/Icon';
+
+const Records = ({
+       first,
+       second,
+       third,
+}) => <Row>
+       <Col>
+               <div className="record-box">
+                       <span className="icon">
+                               <Icon.FIRST_PLACE className="text-gold" />
+                       </span>
+                       <span className="count">
+                               {first}
+                       </span>
+               </div>
+       </Col>
+       <Col>
+               <div className="record-box">
+                       <span className="icon">
+                               <Icon.SECOND_PLACE className="text-silver" />
+                       </span>
+                       <span className="count">
+                               {second}
+                       </span>
+               </div>
+       </Col>
+       <Col>
+               <div className="record-box">
+                       <span className="icon">
+                               <Icon.THIRD_PLACE className="text-bronze" />
+                       </span>
+                       <span className="count">
+                               {third}
+                       </span>
+               </div>
+       </Col>
+</Row>;
+
+Records.propTypes = {
+       first: PropTypes.number,
+       second: PropTypes.number,
+       third: PropTypes.number,
+};
+
+export default Records;
diff --git a/resources/js/components/zootr/MixedPoolsTracker.jsx b/resources/js/components/zootr/MixedPoolsTracker.jsx
new file mode 100644 (file)
index 0000000..ee7f954
--- /dev/null
@@ -0,0 +1,3288 @@
+import FuzzySearch from 'fuzzy-search';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import Icon from '../common/Icon';
+
+const AREAS = [
+       {
+               id: 'kf',
+               bgColor: '#6aa84f',
+               fgColor: '#000000',
+               name: 'Kokiri Forest',
+               short: 'KF',
+               map: {
+                       pos: { x: 210, y: 240 },
+                       size: { x: 150, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/kf.png',
+                               off: { x: 0, y: 0 },
+                               scale: 1.3,
+                       },
+                       labelPos: { x: 90, y: 70 },
+               },
+               entrances: [
+                       {
+                               id: 'bro',
+                               bgColor: '#b6d7a8',
+                               fgColor: '#000000',
+                               name: 'Know-It-All Brothers\' House',
+                               short: 'Bros',
+                               type: 'Interior',
+                               pos: { x: 13, y: 57 },
+                       },
+                       {
+                               id: 'link',
+                               bgColor: '#b6d7a8',
+                               fgColor: '#000000',
+                               name: 'Link\'s House',
+                               short: 'Links',
+                               type: 'SpecialInterior',
+                               pos: { x: 36, y: 74 },
+                       },
+                       {
+                               id: 'sariah',
+                               bgColor: '#b6d7a8',
+                               fgColor: '#000000',
+                               name: 'Sariah\'s House',
+                               short: 'Sariahs',
+                               type: 'Interior',
+                               pos: { x: 47, y: 66 },
+                       },
+                       {
+                               id: 'twin',
+                               bgColor: '#b6d7a8',
+                               fgColor: '#000000',
+                               name: 'House of Twins',
+                               short: 'Twins',
+                               type: 'Interior',
+                               pos: { x: 58, y: 64 },
+                       },
+                       {
+                               id: 'shop',
+                               bgColor: '#b6d7a8',
+                               fgColor: '#000000',
+                               name: 'Kokiri Shop',
+                               short: 'Shop',
+                               type: 'Interior',
+                               pos: { x: 53, y: 42 },
+                       },
+                       {
+                               id: 'mido',
+                               bgColor: '#b6d7a8',
+                               fgColor: '#000000',
+                               name: 'Great Mido\'s House',
+                               short: 'Mido',
+                               type: 'Interior',
+                               pos: { x: 28, y: 38 },
+                       },
+                       {
+                               id: 'deku',
+                               bgColor: '#ead1dc',
+                               fgColor: '#000000',
+                               name: 'Deku Tree',
+                               short: 'Deku',
+                               spacer: true,
+                               type: 'Dungeon',
+                               pos: { x: 114, y: 26 },
+                       },
+                       {
+                               id: 'storms',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Storms Grotto',
+                               short: 'Storms Grotto',
+                               type: 'Grotto',
+                               pos: { x: 25, y: 25 },
+                       },
+                       {
+                               id: 'hf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Hyrule Field',
+                               short: 'HF',
+                               type: 'Overworld',
+                               pos: { x: 4, y: 45 },
+                       },
+                       {
+                               id: 'lw',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Lost Woods',
+                               short: 'LW',
+                               type: 'Overworld',
+                               pos: { x: 31, y: 21 },
+                       },
+               ],
+       },
+       {
+               id: 'lw',
+               bgColor: '#38761d',
+               fgColor: '#000000',
+               name: 'Lost Woods',
+               short: 'LW',
+               map: {
+                       pos: { x: 370, y: 220 },
+                       size: { x: 75, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/lw.png',
+                               off: { x: 0, y: 0 },
+                               scale: 1.3,
+                       },
+                       labelPos: { x: 40, y: 85 },
+               },
+               entrances: [
+                       {
+                               id: 'gcg',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Goron City Grotto',
+                               short: 'GC Grotto',
+                               type: 'Grotto',
+                               pos: { x: 45, y: 40 },
+                       },
+                       {
+                               id: 'tg',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Theater Grotto',
+                               short: 'Theater Grotto',
+                               type: 'Grotto',
+                               pos: { x: 32, y: 25 },
+                       },
+                       {
+                               id: 'sfmg',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'SFM Grotto',
+                               short: 'SFM Grotto',
+                               type: 'Grotto',
+                               pos: { x: 40, y: 12 },
+                       },
+                       {
+                               id: 'kf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Kokiri Forest',
+                               short: 'KF',
+                               spacer: true,
+                               type: 'Overworld',
+                               pos: { x: 31, y: 60 },
+                       },
+                       {
+                               id: 'gc',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Goron City',
+                               short: 'GC',
+                               type: 'Overworld',
+                               pos: { x: 44, y: 33 },
+                       },
+                       {
+                               id: 'zr',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Zora\'s River',
+                               short: 'ZR',
+                               type: 'Overworld',
+                               pos: { x: 68, y: 38 },
+                       },
+                       {
+                               id: 'sfm',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Sacred Forest Maedows',
+                               short: 'SFM',
+                               type: 'Overworld',
+                               pos: { x: 45, y: 6 },
+                       },
+               ],
+       },
+       {
+               id: 'sfm',
+               bgColor: '#274e13',
+               fgColor: '#000000',
+               name: 'Sacred Forest Maedows',
+               short: 'SFM',
+               map: {
+                       pos: { x: 460, y: 220 },
+                       size: { x: 35, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/sfm.png',
+                               off: { x: -20, y: 0 },
+                               scale: 4.3,
+                       },
+                       labelPos: { x: 15, y: 110 },
+               },
+               entrances: [
+                       {
+                               id: 'forest',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Forest Temple',
+                               short: 'Forest Temple',
+                               type: 'Dungeon',
+                               pos: { x: 18, y: 5 },
+                       },
+                       {
+                               id: 'wolf',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Wolf Grotto',
+                               short: 'Wolf Grotto',
+                               type: 'Grotto',
+                               pos: { x: 14, y: 87 },
+                       },
+                       {
+                               id: 'fairy',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Fairy Grotto',
+                               short: 'Fairy Grotto',
+                               type: 'Grotto',
+                               pos: { x: 18, y: 60 },
+                       },
+                       {
+                               id: 'storms',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Storms Grotto',
+                               short: 'Storms Grotto',
+                               type: 'Grotto',
+                               pos: { x: 25, y: 18 },
+                       },
+                       {
+                               id: 'lw',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Lost Woods',
+                               short: 'LW',
+                               type: 'Overworld',
+                               pos: { x: 14, y: 95 },
+                       },
+               ],
+       },
+       {
+               id: 'gy',
+               bgColor: '#a64d79',
+               fgColor: '#000000',
+               name: 'Graveyard',
+               short: 'Grave',
+               map: {
+                       pos: { x: 310, y: 170 },
+                       size: { x: 100, y: 35, },
+                       bg: {
+                               src: '/media/oot/minimap/gy.png',
+                               off: { x: 0, y: -5 },
+                               scale: 1.5,
+                       },
+                       labelPos: { x: 65, y: 35 },
+               },
+               entrances: [
+                       {
+                               id: 'dh',
+                               bgColor: '#c27ba0',
+                               fgColor: '#000000',
+                               name: 'Dampe Hut',
+                               short: 'Dampe Hut',
+                               type: 'Interior',
+                               pos: { x: 22, y: 26 },
+                       },
+                       {
+                               id: 'shadow',
+                               bgColor: '#c27ba0',
+                               fgColor: '#000000',
+                               name: 'Shadow Temple',
+                               short: 'Shadow',
+                               type: 'Dungeon',
+                               pos: { x: 90, y: 16 },
+                       },
+                       {
+                               id: 'shield',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Shield Grave',
+                               short: 'Shield Grave',
+                               type: 'Grave',
+                               pos: { x: 30, y: 19 },
+                       },
+                       {
+                               id: 'race',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Dampe Race',
+                               short: 'Dampe Race',
+                               type: 'Grave',
+                               pos: { x: 25, y: 7 },
+                       },
+                       {
+                               id: 'sun',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Sun Song Grave',
+                               short: 'Sun Song Gr',
+                               type: 'Grave',
+                               pos: { x: 41, y: 21 },
+                       },
+                       {
+                               id: 'family',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Family Tomb',
+                               short: 'Family Tomb',
+                               type: 'Grave',
+                               pos: { x: 52, y: 15 },
+                       },
+                       {
+                               id: 'kak',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Kakariko',
+                               short: 'Kak',
+                               type: 'Overworld',
+                               pos: { x: 5, y: 20 },
+                       },
+               ],
+       },
+       {
+               id: 'kak',
+               bgColor: '#ff9900',
+               fgColor: '#000000',
+               name: 'Kakariko Village',
+               short: 'Kak',
+               map: {
+                       pos: { x: 190, y: 140 },
+                       size: { x: 125, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/kak.png',
+                               off: { x: -7, y: 0 },
+                               scale: 1.7,
+                       },
+                       labelPos: { x: 20, y: 95 },
+               },
+               entrances: [
+                       {
+                               id: 'talon',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Carpenter Boss House',
+                               short: 'Talons',
+                               type: 'Interior',
+                               pos: { x: 66, y: 51 },
+                       },
+                       {
+                               id: 'skull',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Skulltula House',
+                               short: 'Skulltula',
+                               type: 'Interior',
+                               pos: { x: 58, y: 73 },
+                       },
+                       {
+                               id: 'impaf',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Impa Front',
+                               short: 'Impa Front',
+                               type: 'Interior',
+                               pos: { x: 58, y: 92 },
+                       },
+                       {
+                               id: 'impab',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Impa Back',
+                               short: 'Impa Back',
+                               type: 'Interior',
+                               pos: { x: 71, y: 91 },
+                       },
+                       {
+                               id: 'shield',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Shield Shop (Bazaar)',
+                               short: 'Shield Shop',
+                               type: 'Interior',
+                               pos: { x: 60, y: 28 },
+                       },
+                       {
+                               id: 'potion',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Potion Shop',
+                               short: 'Potion Shop',
+                               type: 'SpecialInterior',
+                               pos: { x: 70, y: 28 },
+                       },
+                       {
+                               id: 'back',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Shop Back',
+                               short: 'Shop Back',
+                               type: 'SpecialInterior',
+                               pos: { x: 80, y: 28 },
+                       },
+                       {
+                               id: 'witch',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Witch',
+                               short: 'Witch',
+                               type: 'Interior',
+                               pos: { x: 84, y: 46 },
+                       },
+                       {
+                               id: 'arch',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Archery',
+                               short: 'Archery',
+                               type: 'Interior',
+                               pos: { x: 72, y: 67 },
+                       },
+                       {
+                               id: 'mill',
+                               bgColor: '#f9cb9c',
+                               fgColor: '#000000',
+                               name: 'Windmill',
+                               short: 'Windmill',
+                               type: 'SpecialInterior',
+                               pos: { x: 96, y: 59 },
+                       },
+                       {
+                               id: 'botw',
+                               bgColor: '#a64d79',
+                               fgColor: '#000000',
+                               name: 'Bottom of the Well',
+                               short: 'Bottom Well',
+                               spacer: true,
+                               type: 'Dungeon',
+                               pos: { x: 84, y: 59 },
+                       },
+                       {
+                               id: 'open',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Open Grotto',
+                               short: 'Open Grotto',
+                               type: 'Grotto',
+                               pos: { x: 86, y: 37 },
+                       },
+                       {
+                               id: 'redead',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Redead Grotto',
+                               short: 'Redead Grotto',
+                               type: 'Grotto',
+                               pos: { x: 58, y: 57 },
+                       },
+                       {
+                               id: 'hf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Hyrule Field',
+                               short: 'HF',
+                               type: 'Overworld',
+                               pos: { x: 10, y: 74 },
+                       },
+                       {
+                               id: 'dmt',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Death Mountain Trail',
+                               short: 'DMT',
+                               type: 'Overworld',
+                               pos: { x: 67, y: 8 },
+                       },
+                       {
+                               id: 'gy',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Graveyard',
+                               short: 'Grave',
+                               type: 'Overworld',
+                               pos: { x: 112, y: 83 },
+                       },
+               ],
+       },
+       {
+               id: 'm1',
+               bgColor: '#9900ff',
+               fgColor: '#000000',
+               name: 'Market 1',
+               short: 'M1',
+               map: {
+                       pos: { x: 100, y: 80 },
+                       size: { x: 100, y: 60, },
+                       bg: {
+                               src: '/media/oot/minimap/m1.png',
+                               off: { x: 0, y: -6 },
+                               scale: 1.0,
+                       },
+                       labelPos: { x: 38, y: 30 },
+               },
+               entrances: [
+                       {
+                               id: 'shield',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Shield Shop',
+                               short: 'Shield Shop',
+                               type: 'Interior',
+                               pos: { x: 81, y: 36 },
+                       },
+                       {
+                               id: 'potion',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Potion Shop',
+                               short: 'Potion Shop',
+                               type: 'Interior',
+                               pos: { x: 81, y: 27 },
+                       },
+                       {
+                               id: 'mask',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Mask Shop',
+                               short: 'Mask Shop',
+                               type: 'Interior',
+                               pos: { x: 75, y: 14 },
+                       },
+                       {
+                               id: 'sling',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Slingshot Game',
+                               short: 'Sling Game',
+                               type: 'Interior',
+                               pos: { x: 60, y: 14 },
+                       },
+                       {
+                               id: 'chuu',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Bombchu Bowling',
+                               short: 'Bombchu',
+                               type: 'Interior',
+                               pos: { x: 54, y: 30 },
+                       },
+                       {
+                               id: 'tcg',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Treasure Chest Game',
+                               short: 'TCG',
+                               type: 'Interior',
+                               pos: { x: 52, y: 48 },
+                       },
+                       {
+                               id: 'alleyl',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Backalley Left',
+                               short: 'Alley L',
+                               type: 'Overworld',
+                               pos: { x: 26, y: 48 },
+                       },
+                       {
+                               id: 'alleyr',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Backalley Right',
+                               short: 'Alley R',
+                               type: 'Overworld',
+                               pos: { x: 18, y: 10 },
+                       },
+                       {
+                               id: 'tot',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Temple of Time',
+                               short: 'ToT',
+                               type: 'Overworld',
+                               pos: { x: 92, y: 15 },
+                       },
+                       {
+                               id: 'hc',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Hyrule Castle',
+                               short: 'HC',
+                               type: 'Overworld',
+                               pos: { x: 67, y: 7 },
+                       },
+                       {
+                               id: 'm2',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Market 2',
+                               short: 'M2',
+                               type: 'Overworld',
+                               pos: { x: 66, y: 50 },
+                       },
+               ],
+       },
+       {
+               id: 'm2',
+               bgColor: '#9900ff',
+               fgColor: '#000000',
+               name: 'Market 2',
+               short: 'M2',
+               map: {
+                       pos: { x: 205, y: 85 },
+                       size: { x: 18, y: 50, },
+                       bg: {
+                               src: '/media/oot/minimap/m2.png',
+                               off: { x: -3, y: -3 },
+                               scale: 3.6,
+                       },
+                       labelPos: { x: -2, y: 25 },
+               },
+               entrances: [
+                       {
+                               id: 'bp',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Big Poe',
+                               short: 'Big Poe',
+                               type: 'Interior',
+                               pos: { x: 15.5, y: 32 },
+                       },
+                       {
+                               id: 'hf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Hyrule Field',
+                               short: 'HF',
+                               type: 'Overworld',
+                               pos: { x: 8.5, y: 47.5 },
+                       },
+                       {
+                               id: 'm1',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Market 1',
+                               short: 'M1',
+                               type: 'Overworld',
+                               pos: { x: 8.5, y: 3 },
+                       },
+               ],
+       },
+       {
+               id: 'hc',
+               bgColor: '#bf9000',
+               fgColor: '#000000',
+               name: 'Hyrule Castle',
+               short: 'HC',
+               map: {
+                       pos: { x: 100, y: 0 },
+                       size: { x: 120, y: 70, },
+                       bg: {
+                               src: '/media/oot/minimap/hc-gc.png',
+                               off: { x: 0, y: 0 },
+                               scale: 1.2,
+                       },
+                       labelPos: { x: 25, y: 65 },
+               },
+               entrances: [
+                       {
+                               id: 'hcfairy',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Hyrule Castle Fairy',
+                               short: 'HC Fairy',
+                               type: 'Interior',
+                               pos: { x: 61, y: 23 },
+                       },
+                       {
+                               id: 'gfairy',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Ganon\'s Castle Fairy',
+                               short: 'Ganon Fairy',
+                               type: 'Interior',
+                               pos: { x: 116, y: 51 },
+                       },
+                       {
+                               id: 'igc',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Inside Ganon\'s Castle',
+                               short: 'IGC',
+                               type: 'DungeonSpecial',
+                               pos: { x: 83, y: 30 },
+                       },
+                       {
+                               id: 'storms',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Storms Grotto',
+                               short: 'Storms Grotto',
+                               type: 'Grotto',
+                               pos: { x: 30, y: 29 },
+                       },
+                       {
+                               id: 'm1',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Market 1',
+                               short: 'M1',
+                               type: 'Overworld',
+                               pos: { x: 60, y: 66 },
+                       },
+               ],
+       },
+       {
+               id: 'hf',
+               bgColor: '#674ea7',
+               fgColor: '#000000',
+               name: 'Hyrule Field',
+               short: 'HF',
+               map: {
+                       pos: { x: 90, y: 150 },
+                       size: { x: 100, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/hf.png',
+                               off: { x: -16, y: 0 },
+                               scale: 1.8,
+                       },
+                       labelPos: { x: 100, y: 10 },
+               },
+               entrances: [
+                       {
+                               id: 'destiny',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Destiny Grotto',
+                               short: 'Destiny Grotto',
+                               type: 'Grotto',
+                               pos: { x: 33, y: 7 },
+                       },
+                       {
+                               id: 'tektite',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Tektite Grotto',
+                               short: 'Tektite',
+                               type: 'Grotto',
+                               pos: { x: 30, y: 23 },
+                       },
+                       {
+                               id: 'nw',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Northwest Grotto (near Market)',
+                               short: 'NW Grotto',
+                               type: 'Grotto',
+                               pos: { x: 48, y: 13 },
+                       },
+                       {
+                               id: 'nk',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Grotto near Kakariko',
+                               short: 'near Kak Gro',
+                               type: 'Grotto',
+                               pos: { x: 68, y: 8 },
+                       },
+                       {
+                               id: 'se',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Southeast Grotto',
+                               short: 'SE Grotto',
+                               type: 'Grotto',
+                               pos: { x: 55, y: 78 },
+                       },
+                       {
+                               id: 'open',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Open Grotto',
+                               short: 'Open Grotto',
+                               type: 'Grotto',
+                               pos: { x: 35, y: 86 },
+                       },
+                       {
+                               id: 'sg',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'South Grotto',
+                               short: 'South Grotto',
+                               type: 'Grotto',
+                               pos: { x: 28, y: 87 },
+                       },
+                       {
+                               id: 'cow',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Cow Grotto',
+                               short: 'Cow Grotto',
+                               type: 'Grotto',
+                               pos: { x: 13, y: 47 },
+                       },
+                       {
+                               id: 'town',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Town',
+                               short: 'Town',
+                               spacer: true,
+                               type: 'Overworld',
+                               pos: { x: 57, y: 10 },
+                       },
+                       {
+                               id: 'llr',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Lon Lon Ranch',
+                               short: 'LLR',
+                               type: 'Overworld',
+                               pos: { x: 45, y: 44 },
+                       },
+                       {
+                               id: 'kak',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Kakariko',
+                               short: 'Kak',
+                               type: 'Overworld',
+                               pos: { x: 80, y: 10 },
+                       },
+                       {
+                               id: 'zr',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Zora\'s River',
+                               short: 'ZR',
+                               type: 'Overworld',
+                               pos: { x: 94, y: 30 },
+                       },
+                       {
+                               id: 'kf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Kokiri Forest',
+                               short: 'KF',
+                               type: 'Overworld',
+                               pos: { x: 87, y: 57 },
+                       },
+                       {
+                               id: 'lh',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Lake Hylia',
+                               short: 'LH',
+                               type: 'Overworld',
+                               pos: { x: 25, y: 95 },
+                       },
+                       {
+                               id: 'gv',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Gerudo Valley',
+                               short: 'GV',
+                               type: 'Overworld',
+                               pos: { x: 6, y: 51 },
+                       },
+               ],
+       },
+       {
+               id: 'zr',
+               bgColor: '#3c78d8',
+               fgColor: '#000000',
+               name: 'Zora\'s River',
+               short: 'ZR',
+               map: {
+                       pos: { x: 330, y: 100 },
+                       size: { x: 100, y: 60, },
+                       bg: {
+                               src: '/media/oot/minimap/zr.png',
+                               off: { x: 0, y: 0 },
+                               scale: 1.3,
+                       },
+                       labelPos: { x: 60, y: 40 },
+               },
+               entrances: [
+                       {
+                               id: 'storms',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Storms Grotto',
+                               short: 'Storms Grotto',
+                               type: 'Grotto',
+                               pos: { x: 8, y: 28 },
+                       },
+                       {
+                               id: 'open',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Open Grotto',
+                               short: 'Open Grotto',
+                               type: 'Grotto',
+                               pos: { x: 36, y: 32 },
+                       },
+                       {
+                               id: 'boulder',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Boulder Grotto',
+                               short: 'Boulder Grotto',
+                               type: 'Grotto',
+                               pos: { x: 40, y: 24 },
+                       },
+                       {
+                               id: 'hf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Hyrule Field',
+                               short: 'HF',
+                               spacer: true,
+                               type: 'Overworld',
+                               pos: { x: 10, y: 52 },
+                       },
+                       {
+                               id: 'lw',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Lost Woods',
+                               short: 'LW',
+                               type: 'Overworld',
+                               pos: { x: 90.5, y: 18 },
+                       },
+                       {
+                               id: 'zd',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Zora\'s Domain',
+                               short: 'ZD',
+                               type: 'Overworld',
+                               pos: { x: 96, y: 9 },
+                       },
+               ],
+       },
+       {
+               id: 'zd',
+               bgColor: '#3c78d8',
+               fgColor: '#000000',
+               name: 'Zora\'s Domain',
+               short: 'ZD',
+               map: {
+                       pos: { x: 410, y: 100 },
+                       size: { x: 80, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/zd.png',
+                               off: { x: -15, y: -5 },
+                               scale: 2.3,
+                       },
+                       labelPos: { x: 18, y: 40 },
+               },
+               entrances: [
+                       {
+                               id: 'shop',
+                               bgColor: '#aac2f1',
+                               fgColor: '#000000',
+                               name: 'Shop',
+                               short: 'Shop',
+                               type: 'Interior',
+                               pos: { x: 55, y: 85 },
+                       },
+                       {
+                               id: 'storms',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Storms Grotto',
+                               short: 'Storms Grotto',
+                               type: 'Grotto',
+                               pos: { x: 16, y: 64 },
+                       },
+                       {
+                               id: 'zr',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Zora\'s River',
+                               short: 'ZR',
+                               type: 'Overworld',
+                               pos: { x: 6, y: 73 },
+                       },
+                       {
+                               id: 'lh',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Lake Hylia',
+                               short: 'LH',
+                               type: 'Overworld',
+                               pos: { x: 35, y: 72 },
+                       },
+                       {
+                               id: 'zf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Zora\'s Fountain',
+                               short: 'ZF',
+                               type: 'Overworld',
+                               pos: { x: 58, y: 15 },
+                       },
+               ],
+       },
+       {
+               id: 'zf',
+               bgColor: '#3c78d8',
+               fgColor: '#000000',
+               name: 'Zora\'s Fountain',
+               short: 'ZF',
+               map: {
+                       pos: { x: 410, y: 0 },
+                       size: { x: 90, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/zf.png',
+                               off: { x: -5, y: 0 },
+                               scale: 2.1,
+                       },
+                       labelPos: { x: 60, y: 35 },
+               },
+               entrances: [
+                       {
+                               id: 'wall',
+                               bgColor: '#aac2f1',
+                               fgColor: '#000000',
+                               name: 'Fairy Wall',
+                               short: 'Fairy Wall',
+                               type: 'Interior',
+                               pos: { x: 61, y: 90 },
+                       },
+                       {
+                               id: 'jabu',
+                               bgColor: '#ead1dc',
+                               fgColor: '#000000',
+                               name: 'Jabu Jabu\'s Belly',
+                               short: 'Jabu',
+                               type: 'Dungeon',
+                               pos: { x: 34, y: 38 },
+                       },
+                       {
+                               id: 'ice',
+                               bgColor: '#a64d79',
+                               fgColor: '#000000',
+                               name: 'Ice Cavern',
+                               short: 'Ice Cavern',
+                               type: 'Dungeon',
+                               pos: { x: 52, y: 10 },
+                       },
+                       {
+                               id: 'zd',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Zora\'s Domain',
+                               short: 'ZD',
+                               type: 'Overworld',
+                               pos: { x: 12, y: 55 },
+                       },
+               ],
+       },
+       {
+               id: 'lh',
+               bgColor: '#4a86e8',
+               fgColor: '#000000',
+               name: 'Lake Hylia',
+               short: 'LH',
+               map: {
+                       pos: { x: 0, y: 265 },
+                       size: { x: 90, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/lh.png',
+                               off: { x: -15, y: -5 },
+                               scale: 1.9,
+                       },
+                       labelPos: { x: 70, y: 65 },
+               },
+               entrances: [
+                       {
+                               id: 'dive',
+                               bgColor: '#cfe2f3',
+                               fgColor: '#000000',
+                               name: 'Lab Diving',
+                               short: 'Lab Dive',
+                               type: 'Interior',
+                               pos: { x: 30, y: 43 },
+                       },
+                       {
+                               id: 'fishing',
+                               bgColor: '#cfe2f3',
+                               fgColor: '#000000',
+                               name: 'Fishing Game',
+                               short: 'Fishing',
+                               type: 'Interior',
+                               pos: { x: 68, y: 43 },
+                       },
+                       {
+                               id: 'water',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Water Temple',
+                               short: 'Water Temple',
+                               type: 'Dungeon',
+                               pos: { x: 45, y: 65 },
+                       },
+                       {
+                               id: 'owl',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Owl Grotto',
+                               short: 'Owl Grotto',
+                               type: 'Grotto',
+                               pos: { x: 24, y: 65 },
+                       },
+                       {
+                               id: 'hf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Hyrule Field',
+                               short: 'HF',
+                               type: 'Overworld',
+                               pos: { x: 35, y: 5 },
+                       },
+                       {
+                               id: 'zd',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Zora\'s Domain',
+                               short: 'ZD',
+                               type: 'Overworld',
+                               pos: { x: 45, y: 40 },
+                       },
+               ],
+       },
+       {
+               id: 'llr',
+               bgColor: '#f1c232',
+               fgColor: '#000000',
+               name: 'Lon Lon Ranch',
+               short: 'LLR',
+               map: {
+                       pos: { x: 100, y: 260 },
+                       size: { x: 80, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/llr.png',
+                               off: { x: -22, y: -6 },
+                               scale: 2.6,
+                       },
+                       labelPos: { x: 40, y: 50 },
+               },
+               entrances: [
+                       {
+                               id: 'chicken',
+                               bgColor: '#ffd966',
+                               fgColor: '#000000',
+                               name: 'Chicken Game',
+                               short: 'Chicken',
+                               type: 'Interior',
+                               pos: { x: 54, y: 13 },
+                       },
+                       {
+                               id: 'stable',
+                               bgColor: '#ffd966',
+                               fgColor: '#000000',
+                               name: 'Stable',
+                               short: 'Stable',
+                               type: 'Interior',
+                               pos: { x: 50, y: 19 },
+                       },
+                       {
+                               id: 'tower',
+                               bgColor: '#ffd966',
+                               fgColor: '#000000',
+                               name: 'Tower',
+                               short: 'Tower',
+                               type: 'Interior',
+                               pos: { x: 17, y: 82 },
+                       },
+                       {
+                               id: 'grotto',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Grotto',
+                               short: 'Grotto',
+                               type: 'Grotto',
+                               pos: { x: 60, y: 85 },
+                       },
+                       {
+                               id: 'hf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Hyrule Field',
+                               short: 'HF',
+                               type: 'Overworld',
+                               pos: { x: 60, y: 5 },
+                       },
+               ],
+       },
+       {
+               id: 'gv',
+               bgColor: '#b45f06',
+               fgColor: '#000000',
+               name: 'Gerudo Valley',
+               short: 'GV',
+               map: {
+                       pos: { x: 0, y: 190 },
+                       size: { x: 100, y: 75, },
+                       bg: {
+                               src: '/media/oot/minimap/gv.png',
+                               off: { x: -17, y: -5 },
+                               scale: 1.9,
+                       },
+                       labelPos: { x: 20, y: 55 },
+               },
+               entrances: [
+                       {
+                               id: 'tent',
+                               bgColor: '#b45f06',
+                               fgColor: '#000000',
+                               name: 'Tent',
+                               short: 'Tent',
+                               type: 'Interior',
+                               pos: { x: 44, y: 33 },
+                       },
+                       {
+                               id: 'str2',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Strength 2 Grotto',
+                               short: 'Str2 Grotto',
+                               type: 'Grotto',
+                               pos: { x: 60, y: 60 },
+                       },
+                       {
+                               id: 'storms',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Storms Grotto',
+                               short: 'Storms Grotto',
+                               type: 'Grotto',
+                               pos: { x: 39, y: 27 },
+                       },
+                       {
+                               id: 'hf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Hyrule Field',
+                               short: 'HF',
+                               type: 'Overworld',
+                               pos: { x: 93, y: 45 },
+                       },
+                       {
+                               id: 'gf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Gerudo Fortress',
+                               short: 'GF',
+                               type: 'Overworld',
+                               pos: { x: 6, y: 22 },
+                       },
+                       {
+                               id: 'wf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Waterfall',
+                               short: 'Waterfall',
+                               oneway: true,
+                               type: 'OverworldOneWay',
+                               pos: { x: 58, y: 69 },
+                       },
+               ],
+       },
+       {
+               id: 'gf',
+               bgColor: '#b45f06',
+               fgColor: '#000000',
+               name: 'Gerudo Fortress',
+               short: 'GF',
+               map: {
+                       pos: { x: 0, y: 90 },
+                       size: { x: 90, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/gf.png',
+                               off: { x: -5, y: -35 },
+                               scale: 2.5,
+                       },
+                       labelPos: { x: 15, y: 50 },
+               },
+               entrances: [
+                       {
+                               id: 'gtg',
+                               bgColor: '#a64d79',
+                               fgColor: '#000000',
+                               name: 'Gerudo Training Grounds',
+                               short: 'GTG',
+                               type: 'Dungeon',
+                               pos: { x: 48, y: 60 },
+                       },
+                       {
+                               id: 'storms',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Storms Grotto',
+                               short: 'Storms Grotto',
+                               type: 'Grotto',
+                               pos: { x: 52, y: 47 },
+                       },
+                       {
+                               id: 'gv',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Gerudo Valley',
+                               short: 'GV',
+                               type: 'Overworld',
+                               pos: { x: 43, y: 93 },
+                       },
+                       {
+                               id: 'hw',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Haunted Wasteland',
+                               short: 'Waste',
+                               type: 'Overworld',
+                               pos: { x: 7, y: 13 },
+                       },
+               ],
+       },
+       {
+               id: 'dcol',
+               bgColor: '#f1c232',
+               fgColor: '#000000',
+               name: 'Desert Colossus',
+               short: 'DCol',
+               map: {
+                       pos: { x: 0, y: 0 },
+                       size: { x: 100, y: 90, },
+                       bg: {
+                               src: '/media/oot/minimap/dcol.png',
+                               off: { x: 0, y: -2 },
+                               scale: 2.0,
+                       },
+                       labelPos: { x: 50, y: 50 },
+               },
+               entrances: [
+                       {
+                               id: 'spirit',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Spirit Temple',
+                               short: 'Spirit',
+                               type: 'Dungeon',
+                               pos: { x: 10, y: 43.5 },
+                       },
+                       {
+                               id: 'fairy',
+                               bgColor: '#ffd966',
+                               fgColor: '#000000',
+                               name: 'Fairy',
+                               short: 'Fairy',
+                               type: 'Interior',
+                               pos: { x: 62, y: 21 },
+                       },
+                       {
+                               id: 'str2',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Strength 2 Grotto',
+                               short: 'Str2 Grotto',
+                               type: 'Grotto',
+                               pos: { x: 32, y: 28 },
+                       },
+                       {
+                               id: 'hw',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Haunted Wasteland',
+                               short: 'Waste',
+                               type: 'Overworld',
+                               pos: { x: 85, y: 40 },
+                       },
+               ],
+       },
+       {
+               id: 'hw',
+               bgColor: '#f1c232',
+               fgColor: '#000000',
+               name: 'Haunted Wasteland',
+               short: 'Waste',
+               entrances: [
+                       {
+                               id: 'gf',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Gerudo Fortress',
+                               short: 'GF',
+                               type: 'Overworld',
+                               throughway: 'hw.dcol',
+                       },
+                       {
+                               id: 'dcol',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Desert Colossus',
+                               short: 'DCol',
+                               type: 'Overworld',
+                               throughway: 'hw.gf',
+                       },
+               ],
+       },
+       {
+               id: 'dmc',
+               bgColor: '#ff0000',
+               fgColor: '#000000',
+               name: 'Death Mountain Crater',
+               short: 'DMC',
+               map: {
+                       pos: { x: 320, y: 0 },
+                       size: { x: 90, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/dmc.png',
+                               off: { x: -15, y: -3 },
+                               scale: 1.9,
+                       },
+                       labelPos: { x: 52, y: 62 },
+               },
+               entrances: [
+                       {
+                               id: 'fairy',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Fairy',
+                               short: 'Fairy',
+                               type: 'Interior',
+                               pos: { x: 17, y: 68 },
+                       },
+                       {
+                               id: 'fire',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Fire Temple',
+                               short: 'Fire',
+                               type: 'Dungeon',
+                               pos: { x: 48, y: 6 },
+                       },
+                       {
+                               id: 'boulder',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Boulder Grotto',
+                               short: 'Boulder Gro',
+                               type: 'Grotto',
+                               pos: { x: 49, y: 86 },
+                       },
+                       {
+                               id: 'hammer',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Hammer Grotto',
+                               short: 'Hammer Gro',
+                               type: 'Grotto',
+                               pos: { x: 12, y: 35 },
+                       },
+                       {
+                               id: 'gc',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Goron City',
+                               short: 'GC',
+                               type: 'Overworld',
+                               pos: { x: 7, y: 46 },
+                       },
+                       {
+                               id: 'dmt',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Death Mountain Trail',
+                               short: 'DMT',
+                               type: 'Overworld',
+                               pos: { x: 25, y: 90 },
+                       },
+               ],
+       },
+       {
+               id: 'dmt',
+               bgColor: '#ff0000',
+               fgColor: '#000000',
+               name: 'Death Mountain Trail',
+               short: 'DMT',
+               map: {
+                       pos: { x: 280, y: 70 },
+                       size: { x: 40, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/dmt.png',
+                               off: { x: -12, y: 0 },
+                               scale: 3.8,
+                       },
+                       labelPos: { x: -10, y: 50 },
+               },
+               entrances: [
+                       {
+                               id: 'dc',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Dodongo\'s Cavern',
+                               short: 'DC',
+                               type: 'Dungeon',
+                               pos: { x: 8, y: 53 },
+                       },
+                       {
+                               id: 'fairy',
+                               bgColor: '#ea9999',
+                               fgColor: '#000000',
+                               name: 'Fairy',
+                               short: 'Fairy',
+                               type: 'Interior',
+                               pos: { x: 22, y: 10 },
+                       },
+                       {
+                               id: 'storms',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Storms Grotto',
+                               short: 'Storms Grotto',
+                               type: 'Grotto',
+                               pos: { x: 23, y: 48 },
+                       },
+                       {
+                               id: 'cow',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Cow Grotto',
+                               short: 'Cow Grotto',
+                               type: 'Grotto',
+                               pos: { x: 20, y: 57 },
+                       },
+                       {
+                               id: 'kak',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Kakariko',
+                               short: 'Kak',
+                               spacer: true,
+                               type: 'Overworld',
+                               pos: { x: 15, y: 94 },
+                       },
+                       {
+                               id: 'gc',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Goron City',
+                               short: 'GC',
+                               type: 'Overworld',
+                               pos: { x: 24, y: 40 },
+                       },
+                       {
+                               id: 'dmc',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Death Mountain Crater',
+                               short: 'DMC',
+                               type: 'Overworld',
+                               pos: { x: 29, y: 5 },
+                       },
+               ],
+       },
+       {
+               id: 'gc',
+               bgColor: '#ff0000',
+               fgColor: '#000000',
+               name: 'Goron City',
+               short: 'GC',
+               map: {
+                       pos: { x: 220, y: 0 },
+                       size: { x: 90, y: 100, },
+                       bg: {
+                               src: '/media/oot/minimap/gc.png',
+                               off: { x: -2, y: 0 },
+                               scale: 2.0,
+                       },
+                       labelPos: { x: 25, y: 105 },
+               },
+               entrances: [
+                       {
+                               id: 'shop',
+                               bgColor: '#ea9999',
+                               fgColor: '#000000',
+                               name: 'Shop',
+                               short: 'Shop',
+                               type: 'Interior',
+                               pos: { x: 42, y: 50 },
+                       },
+                       {
+                               id: 'times',
+                               bgColor: '#b7b7b7',
+                               fgColor: '#000000',
+                               name: 'Times Grotto',
+                               short: 'Times Grotto',
+                               type: 'Grotto',
+                               pos: { x: 80, y: 17 },
+                       },
+                       {
+                               id: 'dmt',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Death Mountain Trail',
+                               short: 'DMT',
+                               type: 'Overworld',
+                               pos: { x: 50.5, y: 95 },
+                       },
+                       {
+                               id: 'lw',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Lost Woods',
+                               short: 'LW',
+                               type: 'Overworld',
+                               pos: { x: 64, y: 93 },
+                       },
+                       {
+                               id: 'dmc',
+                               bgColor: '#ff6d01',
+                               fgColor: '#000000',
+                               name: 'Death Mountain Crater',
+                               short: 'DMC',
+                               type: 'Overworld',
+                               pos: { x: 51.5, y: 5 },
+                       },
+               ],
+       },
+       {
+               id: 'tot',
+               bgColor: '#ffffff',
+               fgColor: '#000000',
+               name: 'Temple of Time',
+               short: 'ToT',
+               entrances: [
+                       {
+                               id: 'temple',
+                               bgColor: '#b4a7d6',
+                               fgColor: '#000000',
+                               name: 'Temple of Time',
+                               short: 'Temple',
+                               type: 'SpecialInterior',
+                       },
+                       {
+                               id: 'm1',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Market 1',
+                               short: 'M1',
+                               type: 'Overworld',
+                       },
+               ],
+       },
+       {
+               id: 'deku',
+               bgColor: '#ead1dc',
+               fgColor: '#000000',
+               name: 'Deku Tree',
+               short: 'Deku',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#ead1dc',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               type: 'Dungeon',
+                               throughway: 'deku.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#ead1dc',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               type: 'ChildBoss',
+                               throughway: 'deku.main',
+                       },
+               ],
+       },
+       {
+               id: 'gohma',
+               bgColor: '#ead1dc',
+               fgColor: '#000000',
+               name: 'Gohma',
+               short: 'Gohma',
+               type: 'ChildBoss',
+       },
+       {
+               id: 'dc',
+               bgColor: '#ead1dc',
+               fgColor: '#000000',
+               name: 'Dodongo\'s Cavern',
+               short: 'DC',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#ead1dc',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               type: 'Dungeon',
+                               throughway: 'dc.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#ead1dc',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               type: 'ChildBoss',
+                               throughway: 'dc.main',
+                       },
+               ],
+       },
+       {
+               id: 'kd',
+               bgColor: '#ead1dc',
+               fgColor: '#000000',
+               name: 'King Dodongo',
+               short: 'Dodongo',
+               type: 'ChildBoss',
+       },
+       {
+               id: 'jabu',
+               bgColor: '#ead1dc',
+               fgColor: '#000000',
+               name: 'Jabu Jabu\'s Belly',
+               short: 'Jabu',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#ead1dc',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               type: 'Dungeon',
+                               throughway: 'jabu.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#ead1dc',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               type: 'ChildBoss',
+                               throughway: 'jabu.main',
+                       },
+               ],
+       },
+       {
+               id: 'barinade',
+               bgColor: '#ead1dc',
+               fgColor: '#000000',
+               name: 'Barinade',
+               short: 'Barinade',
+               type: 'ChildBoss',
+       },
+       {
+               id: 'forest',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Forest Temple',
+               short: 'Forest',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               spacer: true,
+                               type: 'Dungeon',
+                               throughway: 'forest.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               spacer: true,
+                               type: 'AdultBoss',
+                               throughway: 'forest.main',
+                       },
+               ],
+       },
+       {
+               id: 'pg',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Phantom Ganon',
+               short: 'PG',
+               spacer: true,
+               type: 'AdultBoss',
+       },
+       {
+               id: 'fire',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Fire Temple',
+               short: 'Fire',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               type: 'Dungeon',
+                               throughway: 'fire.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               type: 'AdultBoss',
+                               throughway: 'fire.main',
+                       },
+               ],
+       },
+       {
+               id: 'volvo',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Volvagia',
+               short: 'Volvagia',
+               type: 'AdultBoss',
+       },
+       {
+               id: 'water',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Water Temple',
+               short: 'Water',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               type: 'Dungeon',
+                               throughway: 'water.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               type: 'AdultBoss',
+                               throughway: 'water.main',
+                       },
+               ],
+       },
+       {
+               id: 'morpha',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Morpha',
+               short: 'Morpha',
+               type: 'AdultBoss',
+       },
+       {
+               id: 'shadow',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Shadow Temple',
+               short: 'Shadow',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               type: 'Dungeon',
+                               throughway: 'shadow.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               type: 'AdultBoss',
+                               throughway: 'shadow.main',
+                       },
+               ],
+       },
+       {
+               id: 'bongo',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Bongo Bongo',
+               short: 'Bongo Bongo',
+               type: 'AdultBoss',
+       },
+       {
+               id: 'spirit',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Spirit Temple',
+               short: 'Spirit',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               type: 'Dungeon',
+                               throughway: 'spirit.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#d5a6bd',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               type: 'AdultBoss',
+                               throughway: 'spirit.main',
+                       },
+               ],
+       },
+       {
+               id: 'tr',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Twinrova',
+               short: 'Twinrova',
+               type: 'AdultBoss',
+       },
+       {
+               id: 'igc',
+               bgColor: '#d5a6bd',
+               fgColor: '#000000',
+               name: 'Inside Ganon\'s Castle',
+               short: 'IGC',
+               entrances: [
+                       {
+                               id: 'main',
+                               bgColor: '#a64d79',
+                               fgColor: '#000000',
+                               name: 'Main',
+                               short: 'Main',
+                               spacer: true,
+                               type: 'Dungeon',
+                               throughway: 'igc.end',
+                       },
+                       {
+                               id: 'end',
+                               bgColor: '#a64d79',
+                               fgColor: '#000000',
+                               name: 'End',
+                               short: 'End',
+                               spacer: true,
+                               type: 'SpecialBoss',
+                               throughway: 'igc.main',
+                       },
+               ],
+       },
+       {
+               id: 'ganon',
+               bgColor: '#a64d79',
+               fgColor: '#000000',
+               name: 'Ganon',
+               short: 'Ganon',
+               spacer: true,
+               type: 'SpecialBoss',
+       },
+       {
+               id: 'botw',
+               bgColor: '#a64d79',
+               fgColor: '#000000',
+               name: 'Bottom of the Well',
+               short: 'Bottom Well',
+               type: 'Dungeon',
+       },
+       {
+               id: 'ice',
+               bgColor: '#a64d79',
+               fgColor: '#000000',
+               name: 'Ice Cavern',
+               short: 'Ice Cavern',
+               type: 'Dungeon',
+       },
+       {
+               id: 'gtg',
+               bgColor: '#a64d79',
+               fgColor: '#000000',
+               name: 'Gerudo Training Grounds',
+               short: 'GTG',
+               type: 'Dungeon',
+       },
+       {
+               id: 'songs',
+               bgColor: '#000000',
+               fgColor: '#ffffff',
+               name: 'Warp Songs',
+               short: 'Songs',
+               entrances: [
+                       {
+                               id: 'minuet',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Minuet of Forest',
+                               short: 'Minuet',
+                               oneway: true,
+                               type: 'WarpSong',
+                               icon: '/media/oot/icons/song-minuet.png',
+                       },
+                       {
+                               id: 'bolero',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Bolero of Fire',
+                               short: 'Bolero',
+                               oneway: true,
+                               type: 'WarpSong',
+                               icon: '/media/oot/icons/song-bolero.png',
+                       },
+                       {
+                               id: 'serenade',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Serenade of Water',
+                               short: 'Serenade',
+                               oneway: true,
+                               type: 'WarpSong',
+                               icon: '/media/oot/icons/song-serenade.png',
+                       },
+                       {
+                               id: 'nocturne',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Nocturne of Shadow',
+                               short: 'Nocturne',
+                               oneway: true,
+                               type: 'WarpSong',
+                               icon: '/media/oot/icons/song-nocturne.png',
+                       },
+                       {
+                               id: 'requiem',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Requiem of Spirit',
+                               short: 'Requiem',
+                               oneway: true,
+                               type: 'WarpSong',
+                               icon: '/media/oot/icons/song-requiem.png',
+                       },
+                       {
+                               id: 'prelude',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Prelude of Light',
+                               short: 'Prelude',
+                               oneway: true,
+                               type: 'WarpSong',
+                               icon: '/media/oot/icons/song-prelude.png',
+                       },
+               ],
+       },
+       {
+               id: 'spawns',
+               bgColor: '#000000',
+               fgColor: '#ffffff',
+               name: 'Spawns',
+               short: 'Spawns',
+               entrances: [
+                       {
+                               id: 'child',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Child Spawn',
+                               short: 'Child',
+                               oneway: true,
+                               type: 'Spawn',
+                               icon: '/media/oot/icons/link-child.png',
+                               iconSize: 10,
+                       },
+                       {
+                               id: 'adult',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Adult Spawn',
+                               short: 'Adult',
+                               oneway: true,
+                               type: 'Spawn',
+                               icon: '/media/oot/icons/link-adult.png',
+                       },
+               ],
+       },
+       {
+               id: 'owls',
+               bgColor: '#000000',
+               fgColor: '#ffffff',
+               name: 'Owl Drops',
+               short: 'Owls',
+               entrances: [
+                       {
+                               id: 'lhowl',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Lake Hylia Owl',
+                               short: 'LH Owl',
+                               oneway: true,
+                               type: 'OwlDrop',
+                               icon: '/media/oot/icons/owl-lake.png',
+                       },
+                       {
+                               id: 'dmtowl',
+                               bgColor: '#38761d',
+                               fgColor: '#ffffff',
+                               name: 'Death Mountain Trail Owl',
+                               short: 'Trail Owl',
+                               oneway: true,
+                               type: 'OwlDrop',
+                               icon: '/media/oot/icons/owl-trail.png',
+                       },
+               ],
+       },
+];
+
+const DUNGEONS = [
+       {
+               id: 'd1',
+               bgColor: '#ff00ff',
+               fgColor: '#000000',
+               name: 'Dungeon Entrances',
+               short: 'Dungeon Entrances',
+               type: 'main',
+               entrances: [
+                       'deku.main',
+                       'dc.main',
+                       'jabu.main',
+                       'forest.main',
+                       'fire.main',
+                       'water.main',
+                       'shadow.main',
+                       'spirit.main',
+                       'igc.main',
+                       'botw',
+                       'ice',
+                       'gtg',
+               ],
+       },
+       {
+               id: 'd2',
+               bgColor: '#ff00ff',
+               fgColor: '#000000',
+               name: 'Dungeon Exits',
+               short: 'Dungeon Exits',
+               type: 'end',
+               entrances: [
+                       'deku.end',
+                       'dc.end',
+                       'jabu.end',
+                       'forest.end',
+                       'fire.end',
+                       'water.end',
+                       'shadow.end',
+                       'spirit.end',
+                       'igc.end',
+               ],
+       },
+       {
+               id: 'boss',
+               bgColor: '#ff00ff',
+               fgColor: '#000000',
+               name: 'Bosses',
+               short: 'Bosses',
+               entrances: [
+                       'gohma',
+                       'kd',
+                       'barinade',
+                       'pg',
+                       'volvo',
+                       'morpha',
+                       'bongo',
+                       'tr',
+                       'ganon',
+               ],
+       },
+];
+
+const ROOMS = [
+       {
+               id: 'trash',
+               bgColor: '#333333',
+               fgColor: '#dddddd',
+               name: 'Trash',
+               short: 'Trash',
+               multi: true,
+       },
+       {
+               id: 'shop',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Shop',
+               short: 'Shop',
+               multi: true,
+       },
+       {
+               id: 'zlf',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'ZL Fairy',
+               short: 'ZL Fairy',
+               multi: true,
+       },
+       {
+               id: 'toti',
+               bgColor: '#ff0000',
+               fgColor: '#000000',
+               name: 'Temple of Time',
+               short: 'Temple of Time',
+       },
+       {
+               id: 'bcb',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Bombchu Bowling',
+               short: 'Bombchu Bow',
+       },
+       {
+               id: 'fish',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Fishing Game',
+               short: 'Fishing',
+       },
+       {
+               id: 'sling',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Slingshot Game',
+               short: 'Slingshot Game',
+       },
+       {
+               id: 'arch',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Archery Game',
+               short: 'Archery Game',
+       },
+       {
+               id: 'tow',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Lon Lon Ranch Tower',
+               short: 'Ranch Tower',
+       },
+       {
+               id: 'chick',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Chicken Game',
+               short: 'Chicken Game',
+       },
+       {
+               id: 'mill',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Windmill',
+               short: 'Windmill',
+       },
+       {
+               id: 'tomb',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Family Tomb',
+               short: 'Family Tomb',
+       },
+       {
+               id: 'ssg',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Sun Song Grave',
+               short: 'Sun Song Grave',
+       },
+       {
+               id: 'mask',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Mask Shop',
+               short: 'Mask Shop',
+       },
+       {
+               id: 'poe',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Big Poe',
+               short: 'Big Poe',
+       },
+       {
+               id: 'thtr',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Mask Theater',
+               short: 'Mask Theater',
+       },
+       {
+               id: 'skull',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Skulltula House',
+               short: 'Skulltula House',
+       },
+       {
+               id: 'tcg',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Treasute Chest Game',
+               short: 'TCG',
+       },
+       {
+               id: 'lab',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Lab Diving',
+               short: 'Lab Dive',
+       },
+       {
+               id: 'tek',
+               bgColor: '#fffd00',
+               fgColor: '#000000',
+               name: 'Tektite Grotto',
+               short: 'Tektite',
+       },
+];
+
+const TYPE_RESTRICTIONS = {
+       OverworldOneWay: [
+               'WarpSong',
+               'BlueWarp',
+               'OwlDrop',
+               'OverworldOneWay',
+               'Overworld',
+               'Extra',
+       ],
+       OwlDrop: [
+               'WarpSong',
+               'BlueWarp',
+               'OwlDrop',
+               'OverworldOneWay',
+               'Overworld',
+               'Extra',
+       ],
+       Spawn: [
+               'Spawn',
+               'WarpSong',
+               'BlueWarp',
+               'OwlDrop',
+               'OverworldOneWay',
+               'Overworld',
+               'Interior',
+               'SpecialInterior',
+               'Extra',
+       ],
+       WarpSong: [
+               'Spawn',
+               'WarpSong',
+               'BlueWarp',
+               'OwlDrop',
+               'OverworldOneWay',
+               'Overworld',
+               'Interior',
+               'SpecialInterior',
+               'Extra',
+       ],
+};
+
+const CONTEXT = React.createContext({});
+
+const useTracker = () => React.useContext(CONTEXT);
+
+const mapEntrance = (area, entrance) => ({
+       ...entrance,
+       id: `${area.id}.${entrance.id}`,
+       area,
+});
+
+const getArea = (id) => {
+       return AREAS.find((area) => area.id === id);
+};
+
+const getEntranceOfArea = (area, entranceId) => {
+       if (!area) return null;
+       if (!area.entrances) return null;
+       const entrance = area.entrances.find((entrance) => entrance.id === entranceId);
+       return mapEntrance(area, entrance);
+};
+
+const getEntrance = (id) => {
+       if (!id) return null;
+       const dotPos = id.indexOf('.');
+       if (dotPos === -1) {
+               return getArea(id);
+       }
+       const areaId = id.substring(0, dotPos);
+       const entranceId = id.substring(dotPos + 1);
+       const area = getArea(areaId);
+       const entrance = getEntranceOfArea(area, entranceId);
+       return entrance;
+};
+
+const getRoom = (id) => {
+       return ROOMS.find((room) => room.id === id);
+};
+
+const entranceShort = (entrance) => {
+       if (!entrance) return null;
+       return entrance.area
+               ? `${entrance.area.short} (${entrance.short})`
+               : entrance.short;
+};
+
+const entranceName = (entrance) => {
+       if (!entrance) return null;
+       return entrance.area
+               ? `[${entrance.area.short}] ${entrance.name}`
+               : entrance.name;
+};
+
+const entranceFull = (entrance) => {
+       if (!entrance) return null;
+       return entrance.area
+               ? `${entrance.area.name} - ${entrance.name}`
+               : entrance.name;
+};
+
+const entranceStyle = (entrance) => {
+       if (!entrance) return null;
+       return {
+               backgroundColor: entrance.bgColor,
+               color: entrance.fgColor,
+       };
+};
+
+const resolvePath = (connections, from) => {
+       if (!connections[from]) return { dst: null, via: [] };
+       const dstEntrance = getEntrance(connections[from]);
+       if (!dstEntrance || !dstEntrance.throughway) return { dst: connections[from], via: [] };
+       const path = resolvePath(connections, dstEntrance.throughway);
+       if (!path.dst) return { dst: connections[from], via: path.via };
+       return { dst: path.dst, via: [connections[from], ...path.via] };
+};
+
+const vecAdd = (a, b) => ({ x: a.x + b.x, y: a.y + b.y });
+
+const vecMul = (v, f) => ({ x: v.x * f, y: v.y * f });
+
+const MAPS = AREAS
+       .filter((area) => !!area.map)
+       .map((area) => ({
+               color: area.bgColor,
+               id: area.id,
+               labelPos: area.map.labelPos ? vecAdd(area.map.pos, area.map.labelPos) : null,
+               name: area.name,
+               pos: area.map.pos,
+               short: area.short,
+               size: area.map.size,
+               bg: {
+                       src: area.map.bg.src,
+                       pos: vecAdd(area.map.pos, area.map.bg.off),
+                       size: vecMul(area.map.size, area.map.bg.scale),
+               },
+               entrances: area.entrances
+                       .filter((entrance) => entrance.pos)
+                       .map((entrance) => ({
+                               id: `${area.id}.${entrance.id}`,
+                               name: entranceFull({ ...entrance, area }),
+                               pos: vecAdd(area.map.pos, entrance.pos),
+                               color: entrance.bgColor,
+                       })),
+       }));
+
+const getMapEntrance = (id) => {
+       if (!id) return null;
+       const dotPos = id.indexOf('.');
+       if (dotPos === -1) {
+               return null;
+       }
+       const areaId = id.substring(0, dotPos);
+       const area = MAPS.find((a) => a.id === areaId);
+       if (!area) return null;
+       const entrance = area.entrances.find((e) => e.id === id);
+       return entrance;
+};
+
+const SelectBox = ({ id, name, onChange, options, value }) => {
+       const [open, setOpen] = React.useState(false);
+       const [search, setSearch] = React.useState('');
+
+       const ref = React.useRef();
+       const searchRef = React.useRef();
+
+       const valueEntrance = React.useMemo(() => getEntrance(value) || getRoom(value), [value]);
+
+       const searcher = React.useMemo(() => {
+               return new FuzzySearch(options, ['id', 'name', 'short', 'fullName'], { sort: true });
+       }, [options]);
+
+       const results = React.useMemo(() => {
+               return searcher.search(search);
+       }, [search, searcher]);
+
+       React.useEffect(() => {
+               const handleEventOutside = e => {
+                       if (ref.current && !ref.current.contains(e.target)) {
+                               setOpen(false);
+                       }
+               };
+               document.addEventListener('mousedown', handleEventOutside, true);
+               document.addEventListener('focus', handleEventOutside, true);
+               return () => {
+                       document.removeEventListener('mousedown', handleEventOutside, true);
+                       document.removeEventListener('focus', handleEventOutside, true);
+               };
+       }, []);
+
+       const classNames = ['entrance-select'];
+       if (open) classNames.push('is-open');
+
+       return <div className={classNames.join(' ')} ref={ref}>
+               <input
+                       className="entrance-search"
+                       id={id}
+                       onChange={({ target: { value } }) => setSearch(value)}
+                       onFocus={() => setOpen(true)}
+                       ref={searchRef}
+                       type="search"
+                       value={search}
+               />
+               <div
+                       aria-controls={`${id}.options`}
+                       aria-expanded={open ? 'true' : 'false'}
+                       aria-haspopup={`${id}.options`}
+                       className="entrance-value"
+                       onClick={() => {
+                               setOpen(true);
+                               searchRef.current.focus();
+                               searchRef.current.select();
+                       }}
+                       onContextMenu={(e) => {
+                               if (value) {
+                                       onChange({ target: { name, value: null } });
+                               } else {
+                                       onChange({ target: { name, value: 'trash' } });
+                                       setSearch('');
+                               }
+                               e.preventDefault();
+                               e.stopPropagation();
+                       }}
+                       role="combobox"
+                       style={entranceStyle(valueEntrance)}
+                       title={entranceFull(valueEntrance)}
+               >
+                       {entranceShort(valueEntrance)}
+               </div>
+               <div className="entrance-options" id={`${id}.options`} role="listbox">
+                       {results.map((entrance) =>
+                               <div
+                                       className="entrance-option"
+                                       key={entrance.id}
+                                       onClick={() => {
+                                               onChange({ target: { name, value: entrance.id } });
+                                               setOpen(false);
+                                               setSearch('');
+                                       }}
+                                       role="option"
+                                       style={entranceStyle(entrance)}
+                               >
+                                       {entranceName(entrance)}
+                               </div>
+                       )}
+               </div>
+       </div>;
+};
+
+SelectBox.propTypes = {
+       className: PropTypes.string,
+       id: PropTypes.string,
+       name: PropTypes.string,
+       onChange: PropTypes.func,
+       options: PropTypes.arrayOf(PropTypes.shape({
+               id: PropTypes.string,
+               name: PropTypes.string,
+       })),
+       value: PropTypes.string,
+};
+
+const EntranceGroup = ({ checked = 0, children, group, total = 0 }) => {
+       return <div className="entrance-group">
+               <h2 style={entranceStyle(group)}>
+                       {entranceName(group)}
+                       {checked && checked !== total ?
+                               <span className="checks">{checked}/{total}</span>
+                       : null}
+               </h2>
+               {children}
+       </div>;
+};
+
+EntranceGroup.propTypes = {
+       checked: PropTypes.number,
+       children: PropTypes.node,
+       group: PropTypes.shape({
+               bgColor: PropTypes.string,
+               fgColor: PropTypes.string,
+               name: PropTypes.string,
+       }),
+       total: PropTypes.number,
+};
+
+const EntranceRow = ({ entranceId }) => {
+       const entrance = React.useMemo(() => getEntrance(entranceId), [entranceId]);
+
+       const { connections, entrances, setConnection } = useTracker();
+
+       const options = React.useMemo(() => {
+               if (entrance.type && TYPE_RESTRICTIONS[entrance.type]) {
+                       return entrances.filter((e) =>
+                               e.type && TYPE_RESTRICTIONS[entrance.type].includes(e.type));
+               }
+               return entrances;
+       }, [entrances]);
+
+       const className = React.useMemo(() => {
+               const classNames = ['entrance-row'];
+               if (entrance.spacer) classNames.push('mt-2');
+               if (connections[entrance.id] === 'trash') classNames.push('is-trash');
+               return classNames.join(' ');
+       }, [entrance, connections]);
+
+       return <div className={className}>
+               <label
+                       className="entrance-label"
+                       htmlFor={entranceId}
+                       style={entranceStyle(entrance)}
+                       title={entranceFull(entrance)}
+               >
+                       {entranceShort(entrance)}
+               </label>
+               <SelectBox
+                       id={entranceId}
+                       name={entranceId}
+                       onChange={({ target: { name, value } }) => setConnection(name, value)}
+                       options={options}
+                       value={connections[entranceId]}
+               />
+       </div>;
+};
+
+EntranceRow.propTypes = {
+       entranceId: PropTypes.string,
+};
+
+const MapEntrance = ({ entrance }) => {
+       const {
+               connections,
+               isDragging,
+               onMapEntranceClick,
+               setConnection,
+       } = useTracker();
+
+       const className = React.useMemo(() => {
+               const cs = ['entrance'];
+               if (connections[entrance.id] === 'trash') cs.push('is-trash');
+               if (isDragging(entrance)) cs.push('is-dragging');
+               return cs.join(' ');
+       }, [connections, entrance, isDragging]);
+
+       const path = React.useMemo(() => {
+               return resolvePath(connections, entrance.id);
+       }, [connections, entrance]);
+
+       const destination = React.useMemo(() => {
+               return getEntrance(path.dst) || getRoom(path.dst);
+       }, [path]);
+
+       const onClick = React.useCallback((e) => {
+               onMapEntranceClick(entrance);
+               e.preventDefault();
+               e.stopPropagation();
+       }, [entrance, onMapEntranceClick]);
+
+       const onContext = React.useCallback((e) => {
+               if (connections[entrance.id]) {
+                       setConnection(entrance.id, null);
+               } else {
+                       setConnection(entrance.id, 'trash');
+               }
+               e.preventDefault();
+               e.stopPropagation();
+       }, [connections, entrance, setConnection]);
+
+       const description = React.useMemo(() => {
+               const parts = [
+                       entranceShort(destination),
+                       ...path.via.map((id) => `via ${entranceShort(getEntrance(id))}`),
+                       `@ ${entranceShort(getEntrance(entrance.id))}`,
+               ];
+               return parts.join(' ');
+       }, [destination, entrance, path]);
+
+       if (destination) {
+               return <rect
+                       x={entrance.pos.x - 3}
+                       y={entrance.pos.y - 3}
+                       width={6}
+                       height={6}
+                       className={className}
+                       fill={destination.bgColor}
+                       stroke={destination.fgColor}
+                       onClick={onClick}
+                       onContextMenu={onContext}
+               >
+                       <title>{description}</title>
+               </rect>;
+       }
+
+       return <circle
+               cx={entrance.pos.x}
+               cy={entrance.pos.y}
+               r="3"
+               className={className}
+               fill={entrance.color}
+               stroke="#000000"
+               onClick={onClick}
+               onContextMenu={onContext}
+       >
+               <title>{entrance.name}</title>
+       </circle>;
+};
+
+MapEntrance.propTypes = {
+       entrance: PropTypes.shape({
+               color: PropTypes.string,
+               id: PropTypes.string,
+               name: PropTypes.string,
+               pos: PropTypes.shape({
+                       x: PropTypes.number,
+                       y: PropTypes.number,
+               })
+       }),
+};
+
+const MapConnector = ({ from, id, isTrash, to, via }) => {
+       const { onConnectorClick } = useTracker();
+
+       const className = React.useMemo(() => {
+               const cs = ['connector'];
+               if (isTrash) cs.push('is-trash');
+               if (via.length) cs.push('is-via');
+               return cs.join(' ');
+       }, [isTrash, via]);
+
+       return <line
+               className={className}
+               onClick={() => onConnectorClick(id)}
+               x1={from.pos.x}
+               y1={from.pos.y}
+               x2={to.pos.x}
+               y2={to.pos.y}
+       />;
+};
+
+MapConnector.propTypes = {
+       from: PropTypes.shape({
+               pos: PropTypes.shape({
+                       x: PropTypes.number,
+                       y: PropTypes.number,
+               })
+       }),
+       id: PropTypes.string,
+       isTrash: PropTypes.bool,
+       to: PropTypes.shape({
+               pos: PropTypes.shape({
+                       x: PropTypes.number,
+                       y: PropTypes.number,
+               })
+       }),
+       via: PropTypes.arrayOf(PropTypes.string),
+};
+
+const MapAnnotation = ({ annotation }) => {
+       return <image
+               className="annotation"
+               href={annotation.icon}
+               x={annotation.pos.x}
+               y={annotation.pos.y}
+               width={annotation.size}
+               height={annotation.size}
+       >
+               <title>{annotation.name}</title>
+       </image>;
+};
+
+MapAnnotation.propTypes = {
+       annotation: PropTypes.shape({
+               icon: PropTypes.string,
+               name: PropTypes.string,
+               pos: PropTypes.shape({
+                       x: PropTypes.number,
+                       y: PropTypes.number,
+               }),
+               size: PropTypes.number,
+       }),
+};
+
+const initPrefs = () => {
+       const dump = localStorage.getItem('zootr.mixed-pools-tracker-prefs');
+       if (dump) {
+               return JSON.parse(dump);
+       }
+       return {
+               showConnectors: true,
+               showEntrances: true,
+               showLabels: true,
+               showMaps: false,
+               showWarps: true,
+       };
+};
+
+const MixedPoolsTracker = () => {
+       const { t } = useTranslation();
+
+       const [connections, setConnections] = React.useState({});
+       const [dragging, setDragging] = React.useState(null);
+       const [prefs, setPrefs] = React.useState(initPrefs());
+       const [trashConnectors, setTrashConnectors] = React.useState([]);
+
+       const setConnection = React.useCallback((src, dst) => {
+               setConnections((c) => {
+                       const newConn = { ...c };
+                       const srcEntrance = getEntrance(src);
+                       const oldTarget = getEntrance(c[src]);
+                       if (oldTarget && (!srcEntrance || !srcEntrance.oneway)) {
+                               // unset old connection
+                               newConn[c[src]] = null;
+                       }
+                       newConn[src] = dst;
+                       if (dst && srcEntrance && !srcEntrance.oneway) {
+                               newConn[dst] = src;
+                       }
+                       return newConn;
+               });
+       }, []);
+
+       const entrances = React.useMemo(() => {
+               const options = [];
+               ROOMS.forEach((room) => {
+                       options.push(room);
+               });
+               AREAS.forEach((area) => {
+                       if (area.entrances) {
+                               area.entrances.forEach((entrance) => {
+                                       if (entrance.oneway) return;
+                                       options.push(getEntranceOfArea(area, entrance.id));
+                               });
+                       } else {
+                               options.push(getEntrance(area.id));
+                       }
+               });
+               return options.map((option) => ({
+                       ...option,
+                       fullName: entranceFull(option),
+               }));
+       }, []);
+
+       const isDragging = React.useCallback((entrance) => {
+               return dragging === entrance.id;
+       }, [dragging]);
+
+       const onMapEntranceClick = React.useCallback((entrance) => {
+               if (dragging) {
+                       if (dragging !== entrance.id) {
+                               setConnection(dragging, entrance.id);
+                       }
+                       setDragging(null);
+               } else {
+                       setDragging(entrance.id);
+               }
+       }, [dragging, setConnection, setDragging]);
+
+       const onConnectorClick = React.useCallback((id) => {
+               setTrashConnectors((tc) => {
+                       if (tc.includes(id)) {
+                               return tc.filter((tid) => tid !== id);
+                       }
+                       return [...tc, id];
+               });
+       }, []);
+
+       const context = React.useMemo(() => ({
+               connections,
+               entrances,
+               isDragging,
+               onConnectorClick,
+               onMapEntranceClick,
+               setConnection,
+       }), [
+               connections,
+               entrances,
+               isDragging,
+               onConnectorClick,
+               onMapEntranceClick,
+               setConnection,
+       ]);
+
+       const superGroups = React.useMemo(() => {
+               const sg = [
+                       {
+                               key: 'one',
+                               groups: ['kf', 'lw', 'sfm', 'gy'],
+                       },
+                       {
+                               key: 'two',
+                               groups: ['kak', 'm1', 'm2', 'hc'],
+                       },
+                       {
+                               key: 'three',
+                               groups: ['hf', 'zr', 'zd', 'zf'],
+                       },
+                       {
+                               key: 'four',
+                               groups: ['lh', 'llr', 'gv', 'gf', 'dcol', 'hw'],
+                       },
+                       {
+                               key: 'five',
+                               groups: ['dmc', 'dmt', 'gc', 'tot'],
+                       },
+               ];
+               sg.forEach((superGroup) => {
+                       superGroup.groups = superGroup.groups.map((areaId) => {
+                               const area = getArea(areaId);
+                               const entranceIds = area.entrances.map((entrance) => `${area.id}.${entrance.id}`);
+                               const checked = entranceIds.filter((entranceId) =>
+                                       Object.entries(connections).find(([a, b]) => b && a === entranceId)
+                               ).length;
+                               return {
+                                       area,
+                                       entranceIds,
+                                       checked,
+                                       total: area.entrances.length,
+                               };
+                       });
+               });
+               return sg;
+       }, [connections]);
+
+       const connectors = React.useMemo(() => {
+               const cs = [];
+               Object.entries(connections).forEach(([from]) => {
+                       const fromEntrance = getEntrance(from);
+                       if (!fromEntrance) return;
+                       const path = resolvePath(connections, from);
+                       if (!path.dst) return;
+                       if (from > path.dst && !fromEntrance.oneway) return;
+                       const fromMap = getMapEntrance(from);
+                       if (!fromMap) return;
+                       const toMap = getMapEntrance(path.dst);
+                       if (!toMap) return;
+                       const id = `${fromMap.id}-${toMap.id}`;
+                       const isTrash = trashConnectors.includes(id);
+                       cs.push({
+                               id,
+                               from: fromMap,
+                               to: toMap,
+                               via: path.via,
+                               isTrash,
+                       });
+               });
+               return cs;
+       }, [connections, trashConnectors]);
+
+       const annotations = React.useMemo(() => {
+               const annotate = [
+                       'songs.minuet',
+                       'songs.bolero',
+                       'songs.serenade',
+                       'songs.nocturne',
+                       'songs.requiem',
+                       'songs.prelude',
+                       'spawns.child',
+                       'spawns.adult',
+                       'owls.lhowl',
+                       'owls.dmtowl',
+               ];
+               const ans = [];
+               annotate.forEach((id) => {
+                       if (!connections[id]) return;
+                       const srcEntrance = getEntrance(id);
+                       if (!srcEntrance) return;
+                       const dstMap = getMapEntrance(connections[id]);
+                       if (!dstMap) return;
+                       ans.push({
+                               icon: srcEntrance.icon,
+                               name: srcEntrance.name,
+                               pos: vecAdd(dstMap.pos, dstMap.annotationOffset || { x: 0, y: 0 }),
+                               size: srcEntrance.iconSize || 8,
+                       });
+               });
+               return ans;
+       }, [connections]);
+
+       const save = React.useCallback(() => {
+               try {
+                       const dump = JSON.stringify({ connections, trashConnectors });
+                       localStorage.setItem('zootr.mixed-pools-tracker-save', dump);
+                       toastr.success(t('general.saveSuccess'));
+               } catch (e) {
+                       toastr.error(t('general.saveError'));
+                       console.error(e);
+               }
+       }, [connections, t, trashConnectors]);
+
+       const load = React.useCallback(() => {
+               try {
+                       const dump = localStorage.getItem('zootr.mixed-pools-tracker-save');
+                       if (!dump) {
+                               toastr.error(t('general.loadError'));
+                               return;
+                       }
+                       const { connections, trashConnectors } = JSON.parse(dump);
+                       if (connections) {
+                               setConnections(connections);
+                       } else {
+                               setConnections({});
+                       }
+                       if (trashConnectors) {
+                               setTrashConnectors(trashConnectors);
+                       } else {
+                               setTrashConnectors([]);
+                       }
+                       toastr.success(t('general.loadSuccess'));
+               } catch (e) {
+                       toastr.error(t('general.loadError'));
+                       console.error(e);
+               }
+       }, [setConnections, t]);
+
+       const reset = React.useCallback(() => {
+               try {
+                       setConnections({});
+                       setTrashConnectors([]);
+                       toastr.success(t('general.resetSuccess'));
+               } catch (e) {
+                       toastr.error(t('general.resetError'));
+               }
+       }, [t]);
+
+       const togglePref = React.useCallback((which) => {
+               setPrefs((oldPrefs) => {
+                       const newPrefs = {
+                               ...oldPrefs,
+                               [which]: !oldPrefs[which],
+                       };
+                       localStorage.setItem('zootr.mixed-pools-tracker-prefs', JSON.stringify(newPrefs));
+                       return newPrefs;
+               });
+       }, []);
+
+       return <CONTEXT.Provider value={context}>
+               <div className="mixed-pools-tracker">
+                       <div className="columns">
+                               {superGroups.map((sg) =>
+                                       <div className="column" key={sg.key}>
+                                               {sg.groups.map(group =>
+                                                       <EntranceGroup
+                                                               checked={group.checked}
+                                                               group={group.area}
+                                                               key={group.area.id}
+                                                               total={group.total}
+                                                       >
+                                                               {group.entranceIds.map((entranceId) =>
+                                                                       <EntranceRow entranceId={entranceId} key={entranceId} />
+                                                               )}
+                                                       </EntranceGroup>
+                                               )}
+                                       </div>
+                               )}
+                       </div>
+                       <div className="columns">
+                               {DUNGEONS.map((area) =>
+                                       <div className="column" key={area.id}>
+                                               <EntranceGroup group={area}>
+                                                       {area.entrances.map((entranceId) =>
+                                                               <EntranceRow
+                                                                       entranceId={entranceId}
+                                                                       key={entranceId}
+                                                               />
+                                                       )}
+                                               </EntranceGroup>
+                                       </div>
+                               )}
+                               <div className="column">
+                                       {AREAS.slice(43, 44).map((area) =>
+                                               <EntranceGroup group={area} key={area.id}>
+                                                       {area.entrances.map((entrance) =>
+                                                               <EntranceRow
+                                                                       entranceId={`${area.id}.${entrance.id}`}
+                                                                       key={entrance.id}
+                                                               />
+                                                       )}
+                                               </EntranceGroup>
+                                       )}
+                               </div>
+                               <div className="column">
+                                       {AREAS.slice(44, 46).map((area) =>
+                                               <EntranceGroup group={area} key={area.id}>
+                                                       {area.entrances.map((entrance) =>
+                                                               <EntranceRow
+                                                                       entranceId={`${area.id}.${entrance.id}`}
+                                                                       key={entrance.id}
+                                                               />
+                                                       )}
+                                               </EntranceGroup>
+                                       )}
+                               </div>
+                       </div>
+                       <div className="map mt-5">
+                               <svg
+                                       viewBox="0 0 500 370"
+                                       onClick={() => { setDragging(null); }}
+                                       onContextMenu={(e) => { e.preventDefault(); e.stopPropagation(); }}
+                               >
+                                       <g className="background">
+                                               {MAPS.map((map) =>
+                                                       <g className="area" key={map.id} title={map.name}>
+                                                               <image
+                                                                       href={map.bg.src}
+                                                                       pointerEvents="none"
+                                                                       x={map.bg.pos.x} y={map.bg.pos.y}
+                                                                       width={map.bg.size.x}
+                                                                       style={{ opacity: prefs.showMaps ? 1 : 0.25 }}
+                                                               />
+                                                               {map.labelPos && prefs.showLabels ?
+                                                                       <text
+                                                                               className="area-label"
+                                                                               x={map.labelPos.x}
+                                                                               y={map.labelPos.y}
+                                                                               fill={map.color}
+                                                                       >
+                                                                               {map.short}
+                                                                       </text>
+                                                               : null}
+                                                       </g>
+                                               )}
+                                       </g>
+                                       {prefs.showConnectors ?
+                                               <g title="connectors">
+                                                       {connectors.map((c) =>
+                                                               <MapConnector
+                                                                       key={c.id}
+                                                                       from={c.from}
+                                                                       id={c.id}
+                                                                       isTrash={c.isTrash}
+                                                                       to={c.to}
+                                                                       via={c.via}
+                                                               />
+                                                       )}
+                                               </g>
+                                       : null}
+                                       {MAPS.map((map) =>
+                                               <g className="area" key={map.id} title={map.name}>
+                                                       {prefs.showEntrances ? map.entrances.map((entrance) =>
+                                                               <MapEntrance key={entrance.id} entrance={entrance} />
+                                                       ) : null}
+                                               </g>
+                                       )}
+                                       {prefs.showWarps ?
+                                               <g title="anotations">
+                                                       {annotations.map((a) =>
+                                                               <MapAnnotation
+                                                                       key={`${a.id}`}
+                                                                       annotation={a}
+                                                               />
+                                                       )}
+                                               </g>
+                                       : null}
+                               </svg>
+                       </div>
+                       <div className="menu-bar">
+                               <div className="button-bar">
+                                       <Button
+                                               onClick={() => togglePref('showConnectors')}
+                                               size="sm"
+                                               variant={prefs.showConnectors ? 'secondary' : 'outline-secondary'}
+                                       >
+                                               Connectors
+                                       </Button>
+                                       <Button
+                                               onClick={() => togglePref('showEntrances')}
+                                               size="sm"
+                                               variant={prefs.showEntrances ? 'secondary' : 'outline-secondary'}
+                                       >
+                                               Entrances
+                                       </Button>
+                                       <Button
+                                               onClick={() => togglePref('showLabels')}
+                                               size="sm"
+                                               variant={prefs.showLabels ? 'secondary' : 'outline-secondary'}
+                                       >
+                                               Labels
+                                       </Button>
+                                       <Button
+                                               onClick={() => togglePref('showMaps')}
+                                               size="sm"
+                                               variant={prefs.showMaps ? 'secondary' : 'outline-secondary'}
+                                       >
+                                               Maps
+                                       </Button>
+                                       <Button
+                                               onClick={() => togglePref('showWarps')}
+                                               size="sm"
+                                               variant={prefs.showWarps ? 'secondary' : 'outline-secondary'}
+                                       >
+                                               Warps
+                                       </Button>
+                               </div>
+                       <div className="button-bar">
+                               <Button
+                                       onClick={save}
+                                       size="sm"
+                                       title={t('button.save')}
+                                       variant="outline-secondary"
+                               >
+                                       <Icon.SAVE title="" />
+                               </Button>
+                               <Button
+                                       onClick={load}
+                                       size="sm"
+                                       title={t('button.load')}
+                                       variant="outline-secondary"
+                               >
+                                       <Icon.LOAD title="" />
+                               </Button>
+                               <Button
+                                       onClick={reset}
+                                       size="sm"
+                                       title={t('button.reset')}
+                                       variant="outline-secondary"
+                               >
+                                       <Icon.RESET title="" />
+                               </Button>
+                       </div>
+                       </div>
+               </div>
+       </CONTEXT.Provider>;
+};
+
+export default MixedPoolsTracker;
diff --git a/resources/js/helpers/AlttpBaseRomContext.js b/resources/js/helpers/AlttpBaseRomContext.js
deleted file mode 100644 (file)
index 87f1345..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-import CRC32 from 'crc-32';
-import localforage from 'localforage';
-import PropTypes from 'prop-types';
-import React from 'react';
-import toastr from 'toastr';
-
-import i18n from '../i18n';
-
-const AlttpBaseRomContext = React.createContext(null);
-
-const AlttpBaseRomProvider = ({ children }) => {
-       const [rom, setRom] = React.useState(null);
-
-       const setRomCallback = React.useCallback(buffer => {
-               if (buffer) {
-                       const crc = CRC32.buf(new Uint8Array(buffer));
-                       if (crc === 0x3322EFFC) {
-                               setRom(buffer);
-                               localforage.setItem('alttpBaseRom', buffer);
-                               toastr.success(i18n.t('alttp.baseRomSet'));
-                       } else {
-                               toastr.error(i18n.t('alttp.baseRomInvalid'));
-                       }
-               } else {
-                       setRom(null);
-                       localforage.removeItem('alttpBaseRom');
-                       toastr.success(i18n.t('alttp.baseRomRemoved'));
-               }
-       }, [setRom]);
-
-       React.useEffect(() => {
-               (async () => {
-                       const stored = await localforage.getItem('alttpBaseRom');
-                       if (stored) {
-                               const crc = CRC32.buf(new Uint8Array(stored));
-                               if (crc == 0x3322EFFC) {
-                                       setRom(stored);
-                               }
-                       }
-               })();
-       }, []);
-
-       return <AlttpBaseRomContext.Provider value={{ rom, setRom: setRomCallback }}>
-               {children}
-       </AlttpBaseRomContext.Provider>;
-};
-
-AlttpBaseRomProvider.propTypes = {
-       children: PropTypes.node,
-};
-
-export const useAlttpBaseRom = () => React.useContext(AlttpBaseRomContext);
-
-export default AlttpBaseRomProvider;
diff --git a/resources/js/helpers/AlttpBaseRomContext.jsx b/resources/js/helpers/AlttpBaseRomContext.jsx
new file mode 100644 (file)
index 0000000..87f1345
--- /dev/null
@@ -0,0 +1,54 @@
+import CRC32 from 'crc-32';
+import localforage from 'localforage';
+import PropTypes from 'prop-types';
+import React from 'react';
+import toastr from 'toastr';
+
+import i18n from '../i18n';
+
+const AlttpBaseRomContext = React.createContext(null);
+
+const AlttpBaseRomProvider = ({ children }) => {
+       const [rom, setRom] = React.useState(null);
+
+       const setRomCallback = React.useCallback(buffer => {
+               if (buffer) {
+                       const crc = CRC32.buf(new Uint8Array(buffer));
+                       if (crc === 0x3322EFFC) {
+                               setRom(buffer);
+                               localforage.setItem('alttpBaseRom', buffer);
+                               toastr.success(i18n.t('alttp.baseRomSet'));
+                       } else {
+                               toastr.error(i18n.t('alttp.baseRomInvalid'));
+                       }
+               } else {
+                       setRom(null);
+                       localforage.removeItem('alttpBaseRom');
+                       toastr.success(i18n.t('alttp.baseRomRemoved'));
+               }
+       }, [setRom]);
+
+       React.useEffect(() => {
+               (async () => {
+                       const stored = await localforage.getItem('alttpBaseRom');
+                       if (stored) {
+                               const crc = CRC32.buf(new Uint8Array(stored));
+                               if (crc == 0x3322EFFC) {
+                                       setRom(stored);
+                               }
+                       }
+               })();
+       }, []);
+
+       return <AlttpBaseRomContext.Provider value={{ rom, setRom: setRomCallback }}>
+               {children}
+       </AlttpBaseRomContext.Provider>;
+};
+
+AlttpBaseRomProvider.propTypes = {
+       children: PropTypes.node,
+};
+
+export const useAlttpBaseRom = () => React.useContext(AlttpBaseRomContext);
+
+export default AlttpBaseRomProvider;
index 315542822d3710d72e2eb875c598e573635634c8..1a5398fdbf9ab1511676274c1f43b0381069f7d2 100644 (file)
@@ -9,3 +9,44 @@ export const patchGuess = (guesses, guess) =>
 
 export const patchWinner = (winners, winner) =>
        [winner, ...(winners || []).filter(w => w.uid !== winner.uid)];
 
 export const patchWinner = (winners, winner) =>
        [winner, ...(winners || []).filter(w => w.uid !== winner.uid)];
+
+export const compareLive = (a, b) => {
+       const a_live = a && a.twitch_live;
+       const b_live = b && b.twitch_live;
+       if (a_live) {
+               if (b_live) {
+                       return 0;
+               }
+               return -1;
+       }
+       if (b_live) {
+               return 1;
+       }
+       return 0;
+};
+
+export const compareName = (a, b) => {
+       const a_name = (a && (a.short_name || a.title)) || '';
+       const b_name = (b && (b.short_name || b.title)) || '';
+       return a_name.localeCompare(b_name);
+};
+
+export const compareTitle = (a, b) => {
+       const a_title = (a && a.title) || '';
+       const b_title = (b && b.title) || '';
+       return a_title.localeCompare(b_title);
+};
+
+export const compareViewers = (a, b) => {
+       const a_viewers = (a && a.twitch_live && a.twitch_viewers) || 0;
+       const b_viewers = (b && b.twitch_live && b.twitch_viewers) || 0;
+       return b_viewers - a_viewers;
+};
+
+export const compareHorstieLog = (a, b) => {
+       const live = compareLive(a, b);
+       if (live) return live;
+       const viewers = compareViewers(a, b);
+       if (viewers) return viewers;
+       return compareName(a, b);
+};
index 696d39a811385f9a7ab357af777ea84377b1da53..dd7c0d81a2e6f48a66992eda45b0c33e12f0711d 100644 (file)
@@ -59,9 +59,15 @@ export const isActive = episode => {
 };
 
 export const isEventSelected = (filter, event) => {
 };
 
 export const isEventSelected = (filter, event) => {
-       return (filter.event || []).includes(event.id);
+       const found = (filter.event || []).includes(event.id);
+       return filter.eventInvert ? !found : found;
 };
 
 };
 
+export const invertEventFilter = (filter) => ({
+       ...filter,
+       eventInvert: filter.eventInvert ? 0 : 1,
+});
+
 export const toggleEventFilter = (events, filter, event) => {
        const eventFilter = filter.event || [];
        if (eventFilter.includes(event.id)) {
 export const toggleEventFilter = (events, filter, event) => {
        const eventFilter = filter.event || [];
        if (eventFilter.includes(event.id)) {
index f928be1def6cd7321fbea0bde747d765929716f9..c39daaab01ceff30f3d494479a79177ff6c56292 100644 (file)
@@ -3,3 +3,27 @@ import moment from 'moment';
 export const getLink = event => `/events/${event.name}`;
 
 export const hasConcluded = event => event && event.end && moment(event.end).isBefore(moment());
 export const getLink = event => `/events/${event.name}`;
 
 export const hasConcluded = event => event && event.end && moment(event.end).isBefore(moment());
+
+export const isEvergreen = event => event && !event.start && !event.end;
+
+export const isOngoing = event => event &&
+       event.start && (!event.end || moment().isBefore(event.end));
+
+export const compareStart = (a, b) => {
+       if (a && a.start) {
+               if (b && b.start) {
+                       if (moment(a.start).isBefore(moment(b.start))) {
+                               return -1;
+                       }
+                       if (moment(b.start).isBefore(moment(a.start))) {
+                               return 1;
+                       }
+                       return 0;
+               }
+               return 1;
+       }
+       if (b && b.start) {
+               return -1;
+       }
+       return 0;
+};
diff --git a/resources/js/helpers/Result.js b/resources/js/helpers/Result.js
deleted file mode 100644 (file)
index 329116d..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-import React from 'react';
-import Icon from '../components/common/Icon';
-
-export const compareResult = (a, b) => {
-       const a_placement = a && a.placement ? a.placement : 0;
-       const b_placement = b && b.placement ? b.placement : 0;
-       if (a_placement) {
-               if (b_placement) {
-                       if (a_placement < b_placement) return -1;
-                       if (b_placement < a_placement) return 1;
-                       return compareUsername(a, b);
-               }
-               return -1;
-       }
-       if (b_placement) {
-               return 1;
-       }
-       return compareUsername(a, b);
-};
-
-export const compareUsername = (a, b) => {
-       const a_name = (a && a.user && a.user.username) || '';
-       const b_name = (b && b.user && b.user.username) || '';
-       return a_name.localeCompare(b_name);
-};
-
-export const formatTime = result => {
-       const hours = `${Math.floor(result.time / 60 / 60)}`;
-       let minutes = `${Math.floor((result.time / 60) % 60)}`;
-       let seconds = `${Math.floor(result.time % 60)}`;
-       while (minutes.length < 2) {
-               minutes = `0${minutes}`;
-       }
-       while (seconds.length < 2) {
-               seconds = `0${seconds}`;
-       }
-       return `${hours}:${minutes}:${seconds}`;
-};
-
-export const getIcon = (result, maySee) => {
-       if (!result || !result.has_finished) {
-               return <Icon.PENDING className="text-muted" size="lg" />;
-       }
-       if (result.forfeit && maySee) {
-               return <Icon.FORFEIT className="text-danger" size="lg" />;
-       }
-       if (result.placement === 1 && maySee) {
-               return <Icon.FIRST_PLACE className="text-gold" size="lg" />;
-       }
-       if (result.placement === 2 && maySee) {
-               return <Icon.SECOND_PLACE className="text-silver" size="lg" />;
-       }
-       if (result.placement === 3 && maySee) {
-               return <Icon.THIRD_PLACE className="text-bronze" size="lg" />;
-       }
-       return <Icon.FINISHED className="text-success" size="lg" />;
-};
-
-export const getTime = (result, maySee) => {
-       if (!result || !maySee) {
-               return null;
-       }
-       if (result.time) {
-               return formatTime(result);
-       }
-       if (result.forfeit) {
-               return 'DNF';
-       }
-       return '?';
-};
-
-export const parseTime = str => {
-       if (!str) return null;
-       return `${str}`.trim().split(/[-.: ]+/).reduce((acc,time) => (60 * acc) + +time, 0);
-};
-
-export default {
-       compareResult,
-       compareUsername,
-       formatTime,
-       getIcon,
-       getTime,
-       parseTime,
-};
diff --git a/resources/js/helpers/Result.jsx b/resources/js/helpers/Result.jsx
new file mode 100644 (file)
index 0000000..ed16f38
--- /dev/null
@@ -0,0 +1,90 @@
+import React from 'react';
+
+import Icon from '../components/common/Icon';
+import { getUserName } from './User';
+
+export const compareUsername = (a, b) => {
+       const a_name = (a && getUserName(a.user)) || '';
+       const b_name = (b && getUserName(b.user)) || '';
+       return a_name.localeCompare(b_name);
+};
+
+export const compareResult = (a, b) => {
+       const a_placement = a && a.placement ? a.placement : 0;
+       const b_placement = b && b.placement ? b.placement : 0;
+       if (a_placement) {
+               if (b_placement) {
+                       if (a_placement < b_placement) return -1;
+                       if (b_placement < a_placement) return 1;
+                       return compareUsername(a, b);
+               }
+               return -1;
+       }
+       if (b_placement) {
+               return 1;
+       }
+       return compareUsername(a, b);
+};
+
+export const formatTime = result => {
+       const hours = `${Math.floor(result.time / 60 / 60)}`;
+       let minutes = `${Math.floor((result.time / 60) % 60)}`;
+       let seconds = `${Math.floor(result.time % 60)}`;
+       while (minutes.length < 2) {
+               minutes = `0${minutes}`;
+       }
+       while (seconds.length < 2) {
+               seconds = `0${seconds}`;
+       }
+       return `${hours}:${minutes}:${seconds}`;
+};
+
+export const getIcon = (result, maySee) => {
+       if (!result || !result.has_finished) {
+               return <Icon.PENDING className="text-muted" size="lg" />;
+       }
+       if (result.forfeit && maySee) {
+               return <Icon.FORFEIT className="text-danger" size="lg" />;
+       }
+       if (result.placement === 1 && maySee) {
+               return <Icon.FIRST_PLACE className="text-gold" size="lg" />;
+       }
+       if (result.placement === 2 && maySee) {
+               return <Icon.SECOND_PLACE className="text-silver" size="lg" />;
+       }
+       if (result.placement === 3 && maySee) {
+               return <Icon.THIRD_PLACE className="text-bronze" size="lg" />;
+       }
+       return <Icon.FINISHED className="text-success" size="lg" />;
+};
+
+export const getTime = (result, maySee) => {
+       if (!result || !maySee) {
+               return null;
+       }
+       if (result.time) {
+               return formatTime(result);
+       }
+       if (result.forfeit) {
+               return 'DNF';
+       }
+       return '?';
+};
+
+export const parseTime = str => {
+       if (!str) return null;
+       return `${str}`.trim().split(/[-.: ]+/).reduce((acc,time) => (60 * acc) + +time, 0);
+};
+
+export const sortByTime = (results) => [...results].sort(compareResult);
+
+export const sortByUsername = (results) => [...results].sort(compareUsername);
+
+export default {
+       compareResult,
+       compareUsername,
+       formatTime,
+       getIcon,
+       getTime,
+       parseTime,
+};
index c7bb811a9c581f80cea1224db8d7d1c35e8d87d8..68579b84815cd15fad98c2c9463af3a8c8553346 100644 (file)
@@ -1,8 +1,13 @@
 import Participant from './Participant';
 import Tournament from './Tournament';
 
 import Participant from './Participant';
 import Tournament from './Tournament';
 
+export const hasResults = (round) => {
+       return round && round.results && round.results.length > 0;
+};
+
 export const isComplete = (tournament, round) => {
        if (!tournament || !tournament.participants) return false;
 export const isComplete = (tournament, round) => {
        if (!tournament || !tournament.participants) return false;
+       if (tournament.type === 'open-async') return false;
        if (!round || !round.results) return false;
        const runners = Tournament.getRunners(tournament);
        if (!runners.length) return false;
        if (!round || !round.results) return false;
        const runners = Tournament.getRunners(tournament);
        if (!runners.length) return false;
@@ -23,11 +28,12 @@ export const patchResult = (round, result) => {
        }
        return {
                ...round,
        }
        return {
                ...round,
-               results: round.results.map(r => r.id === result.id ? result : r),
+               results: round.results.map(r => r.id === result.id ? { ...r, ...result } : r),
        };
 };
 
 export default {
        };
 };
 
 export default {
+       hasResults,
        isComplete,
        patchResult,
 };
        isComplete,
        patchResult,
 };
diff --git a/resources/js/helpers/nl2br.js b/resources/js/helpers/nl2br.js
deleted file mode 100644 (file)
index 60d695a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-
-const nl2br = str => {
-       if (typeof str !== 'string') {
-               return str;
-       }
-       const nl = /(\r\n|\r|\n)/g;
-       return str.split(nl).map((line, index) => {
-               if (line.match(nl)) {
-                       return <br key={index} />;
-               }
-               return line;
-       });
-};
-
-export default nl2br;
diff --git a/resources/js/helpers/nl2br.jsx b/resources/js/helpers/nl2br.jsx
new file mode 100644 (file)
index 0000000..60d695a
--- /dev/null
@@ -0,0 +1,16 @@
+import React from 'react';
+
+const nl2br = str => {
+       if (typeof str !== 'string') {
+               return str;
+       }
+       const nl = /(\r\n|\r|\n)/g;
+       return str.split(nl).map((line, index) => {
+               if (line.match(nl)) {
+                       return <br key={index} />;
+               }
+               return line;
+       });
+};
+
+export default nl2br;
index 23aba6955b2eb2783894497f85bf881ce43bca66..f1be8765ce11134832f6edf8d343efcb010a9b74 100644 (file)
@@ -106,14 +106,14 @@ export const isTournamentAdmin = (user, tournament) => {
        return p && p.roles && p.roles.includes('admin');
 };
 
        return p && p.roles && p.roles.includes('admin');
 };
 
-export const isTournamentCrew = (user, tournament) =>
-       isTournamentAdmin(user, tournament) || isTournamentMonitor(user, tournament);
-
 export const isTournamentMonitor = (user, tournament) => {
        const p = isParticipant(user, tournament);
        return p && p.roles && p.roles.includes('monitor');
 };
 
 export const isTournamentMonitor = (user, tournament) => {
        const p = isParticipant(user, tournament);
        return p && p.roles && p.roles.includes('monitor');
 };
 
+export const isTournamentCrew = (user, tournament) =>
+       isTournamentAdmin(user, tournament) || isTournamentMonitor(user, tournament);
+
 export const hasFinished = (user, round) =>
        user && round && round.results &&
        round.results.find(r => r.user_id == user.id && r.has_finished);
 export const hasFinished = (user, round) =>
        user && round && round.results &&
        round.results.find(r => r.user_id == user.id && r.has_finished);
@@ -135,6 +135,9 @@ export const mayReportResult = (user, tournament) => {
        return isRunner(user, tournament);
 };
 
        return isRunner(user, tournament);
 };
 
+export const mayDeleteRound = (user, tournament, round) =>
+       !tournament.locked && isTournamentAdmin(user, tournament) && !Round.hasResults(round);
+
 export const mayEditRound = (user, tournament) =>
        !tournament.locked && isTournamentAdmin(user, tournament);
 
 export const mayEditRound = (user, tournament) =>
        !tournament.locked && isTournamentAdmin(user, tournament);
 
@@ -151,11 +154,32 @@ export const mayUpdateTournament = (user, tournament) =>
 export const mayViewProtocol = (user, tournament) =>
        isTournamentCrew(user, tournament);
 
 export const mayViewProtocol = (user, tournament) =>
        isTournamentCrew(user, tournament);
 
-export const maySeeResults = (user, tournament, round) =>
-       round.locked ||
-       hasFinished(user, round) ||
-       isTournamentMonitor(user, tournament) ||
-       Round.isComplete(tournament, round);
+export const maySeeResults = (user, tournament, round) => {
+       if (tournament.result_reveal === 'always') {
+               return true;
+       }
+       if (
+               round.locked ||
+               isTournamentMonitor(user, tournament) ||
+               Round.isComplete(tournament, round)
+       ) {
+               return true;
+       }
+       if (tournament.result_reveal === 'finishers') {
+               return hasFinished(user, round);
+       }
+       if (tournament.result_reveal === 'participants') {
+               return isRunner(user, tournament);
+       }
+       return false;
+};
+
+export const maySeeResult = (user, tournament, round, result) => {
+       if (user && result && user.id === result.user_id) {
+               return true;
+       }
+       return maySeeResults(user, tournament, round);
+};
 
 // Twitch
 
 
 // Twitch
 
diff --git a/resources/js/hooks/snes.js b/resources/js/hooks/snes.js
deleted file mode 100644 (file)
index 344c1eb..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import SettingsDialog from '../components/snes/SettingsDialog';
-import SNESSocket from '../helpers/SNESSocket';
-
-const context = React.createContext({});
-
-export const useSNES = () => React.useContext(context);
-
-export const SNESProvider = ({ children }) => {
-       const [enabled, setEnabled] = React.useState(false);
-       const [showSettingsDialog, setShowSettingsDialog] = React.useState(false);
-
-       const sock = React.useRef(null);
-
-       const [settings, setSettings] = React.useState({
-               proto: 'ws',
-               host: 'localhost',
-               port: 23074,
-               device: '',
-       });
-
-       const [status, setStatus] = React.useState({
-               connected: false,
-               device: '',
-               deviceList: [],
-               error: false,
-       });
-
-       React.useEffect(() => {
-               if (sock.current) {
-                       sock.current.close();
-                       sock.current = null;
-               }
-               if (enabled) {
-                       const tryAttach = () => {
-                               const { deviceList } = sock.current;
-                               let device = '';
-                               if (deviceList.includes(settings.device)) {
-                                       device = settings.device;
-                               } else if (deviceList.length > 0) {
-                                       device = deviceList[0];
-                               }
-                               setStatus(s => ({ ...s, device, deviceList }));
-                               if (device) {
-                                       sock.current.attachDevice(device);
-                               }
-                       };
-                       sock.current = new SNESSocket(`${settings.proto}://${settings.host}:${settings.port}`);
-                       sock.current.onclose = () => {
-                               setStatus({
-                                       connected: false,
-                                       device: '',
-                                       deviceList: [],
-                                       error: false,
-                               });
-                       };
-                       sock.current.onerror = (e) => {
-                               setStatus({
-                                       connected: false,
-                                       device: '',
-                                       deviceList: [],
-                                       error: e,
-                               });
-                       };
-                       sock.current.onopen = () => {
-                               setStatus({
-                                       connected: true,
-                                       device: '',
-                                       deviceList: [],
-                                       error: false,
-                               });
-                               sock.current.requestDeviceList(() => {
-                                       tryAttach();
-                               });
-                       };
-                       const watchdog = setInterval(() => {
-                               if (!sock.current.isOpen()) {
-                                       sock.current.open();
-                                       return;
-                               }
-                               if (!sock.current.device) {
-                                       sock.current.requestDeviceList(() => {
-                                               tryAttach();
-                                       });
-                               }
-                       }, 5000);
-                       return () => {
-                               clearInterval(watchdog);
-                       };
-               }
-       }, [enabled, settings]);
-
-       const enable = React.useCallback(() => {
-               setEnabled(prevEnabled => {
-                       if (prevEnabled) return true;
-                       return true;
-               });
-       }, []);
-
-       const disable = React.useCallback(() => {
-               setEnabled(prevEnabled => {
-                       if (!prevEnabled) return false;
-                       return false;
-               });
-       }, []);
-
-       const openSettings = React.useCallback(() => {
-               setShowSettingsDialog(true);
-       }, []);
-
-       const closeSettings = React.useCallback(() => {
-               setShowSettingsDialog(false);
-       }, []);
-
-       const saveSettings = React.useCallback((values) => {
-               setSettings(s => {
-                       const newSettings = { ...s, ...values };
-                       localStorage.setItem('snes.settings', JSON.stringify(newSettings));
-                       return newSettings;
-               });
-               setShowSettingsDialog(false);
-       }, []);
-
-       React.useEffect(() => {
-               const savedSettings = localStorage.getItem('snes.settings');
-               if (savedSettings) {
-                       setSettings(JSON.parse(savedSettings));
-               }
-       }, []);
-
-       const value = React.useMemo(() => {
-               return { disable, enable, enabled, openSettings, settings, sock, status };
-       }, [disable, enable, enabled, openSettings, settings, sock, status]);
-
-       return <context.Provider value={value}>
-               {children}
-               <SettingsDialog
-                       deviceList={status.deviceList}
-                       onHide={closeSettings}
-                       onSubmit={saveSettings}
-                       settings={settings}
-                       show={showSettingsDialog}
-               />
-       </context.Provider>;
-};
-
-SNESProvider.propTypes = {
-       children: PropTypes.node,
-};
diff --git a/resources/js/hooks/snes.jsx b/resources/js/hooks/snes.jsx
new file mode 100644 (file)
index 0000000..344c1eb
--- /dev/null
@@ -0,0 +1,151 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import SettingsDialog from '../components/snes/SettingsDialog';
+import SNESSocket from '../helpers/SNESSocket';
+
+const context = React.createContext({});
+
+export const useSNES = () => React.useContext(context);
+
+export const SNESProvider = ({ children }) => {
+       const [enabled, setEnabled] = React.useState(false);
+       const [showSettingsDialog, setShowSettingsDialog] = React.useState(false);
+
+       const sock = React.useRef(null);
+
+       const [settings, setSettings] = React.useState({
+               proto: 'ws',
+               host: 'localhost',
+               port: 23074,
+               device: '',
+       });
+
+       const [status, setStatus] = React.useState({
+               connected: false,
+               device: '',
+               deviceList: [],
+               error: false,
+       });
+
+       React.useEffect(() => {
+               if (sock.current) {
+                       sock.current.close();
+                       sock.current = null;
+               }
+               if (enabled) {
+                       const tryAttach = () => {
+                               const { deviceList } = sock.current;
+                               let device = '';
+                               if (deviceList.includes(settings.device)) {
+                                       device = settings.device;
+                               } else if (deviceList.length > 0) {
+                                       device = deviceList[0];
+                               }
+                               setStatus(s => ({ ...s, device, deviceList }));
+                               if (device) {
+                                       sock.current.attachDevice(device);
+                               }
+                       };
+                       sock.current = new SNESSocket(`${settings.proto}://${settings.host}:${settings.port}`);
+                       sock.current.onclose = () => {
+                               setStatus({
+                                       connected: false,
+                                       device: '',
+                                       deviceList: [],
+                                       error: false,
+                               });
+                       };
+                       sock.current.onerror = (e) => {
+                               setStatus({
+                                       connected: false,
+                                       device: '',
+                                       deviceList: [],
+                                       error: e,
+                               });
+                       };
+                       sock.current.onopen = () => {
+                               setStatus({
+                                       connected: true,
+                                       device: '',
+                                       deviceList: [],
+                                       error: false,
+                               });
+                               sock.current.requestDeviceList(() => {
+                                       tryAttach();
+                               });
+                       };
+                       const watchdog = setInterval(() => {
+                               if (!sock.current.isOpen()) {
+                                       sock.current.open();
+                                       return;
+                               }
+                               if (!sock.current.device) {
+                                       sock.current.requestDeviceList(() => {
+                                               tryAttach();
+                                       });
+                               }
+                       }, 5000);
+                       return () => {
+                               clearInterval(watchdog);
+                       };
+               }
+       }, [enabled, settings]);
+
+       const enable = React.useCallback(() => {
+               setEnabled(prevEnabled => {
+                       if (prevEnabled) return true;
+                       return true;
+               });
+       }, []);
+
+       const disable = React.useCallback(() => {
+               setEnabled(prevEnabled => {
+                       if (!prevEnabled) return false;
+                       return false;
+               });
+       }, []);
+
+       const openSettings = React.useCallback(() => {
+               setShowSettingsDialog(true);
+       }, []);
+
+       const closeSettings = React.useCallback(() => {
+               setShowSettingsDialog(false);
+       }, []);
+
+       const saveSettings = React.useCallback((values) => {
+               setSettings(s => {
+                       const newSettings = { ...s, ...values };
+                       localStorage.setItem('snes.settings', JSON.stringify(newSettings));
+                       return newSettings;
+               });
+               setShowSettingsDialog(false);
+       }, []);
+
+       React.useEffect(() => {
+               const savedSettings = localStorage.getItem('snes.settings');
+               if (savedSettings) {
+                       setSettings(JSON.parse(savedSettings));
+               }
+       }, []);
+
+       const value = React.useMemo(() => {
+               return { disable, enable, enabled, openSettings, settings, sock, status };
+       }, [disable, enable, enabled, openSettings, settings, sock, status]);
+
+       return <context.Provider value={value}>
+               {children}
+               <SettingsDialog
+                       deviceList={status.deviceList}
+                       onHide={closeSettings}
+                       onSubmit={saveSettings}
+                       settings={settings}
+                       show={showSettingsDialog}
+               />
+       </context.Provider>;
+};
+
+SNESProvider.propTypes = {
+       children: PropTypes.node,
+};
diff --git a/resources/js/hooks/tracker.js b/resources/js/hooks/tracker.js
deleted file mode 100644 (file)
index d0fb6b8..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-
-import {
-       CONFIG,
-       DUNGEONS,
-       applyLogic,
-       configureDungeons,
-       makeEmptyState,
-       mergeStates,
-} from '../helpers/tracker';
-
-const context = React.createContext({});
-
-export const useTracker = () => React.useContext(context);
-
-export const TrackerProvider = ({ children }) => {
-       const [config, setConfig] = React.useState(CONFIG);
-       const [state, setState] = React.useState(makeEmptyState());
-       const [autoState, setAutoState] = React.useState(makeEmptyState());
-       const [manualState, setManualState] = React.useState(makeEmptyState());
-       const [dungeons, setDungeons] = React.useState(DUNGEONS);
-       const [logic, setLogic] = React.useState({});
-       const [pins, setPins] = React.useState([]);
-
-       const saveConfig = React.useCallback((values) => {
-               setConfig(s => {
-                       const newConfig = { ...s, ...values };
-                       localStorage.setItem('tracker.config', JSON.stringify(newConfig));
-                       return newConfig;
-               });
-       }, []);
-
-       const addPin = React.useCallback((pin) => {
-               setPins(ps => {
-                       const id = ps.length ? ps[ps.length - 1].id + 1 : 1;
-                       return [...ps, { ...pin, id }];
-               });
-       }, []);
-
-       const removePin = React.useCallback((pin) => {
-               setPins(ps => ps.filter(p => p.id !== pin.id));
-       }, []);
-
-       React.useEffect(() => {
-               const savedConfig = localStorage.getItem('tracker.config');
-               if (savedConfig) {
-                       setConfig(c => ({ ...c, ...JSON.parse(savedConfig) }));
-               }
-       }, []);
-
-       React.useEffect(() => {
-               const newDungeons = configureDungeons(config);
-               setDungeons(newDungeons);
-       }, [config]);
-
-       React.useEffect(() => {
-               setState(mergeStates(autoState, manualState));
-       }, [autoState, manualState]);
-
-       React.useEffect(() => {
-               setLogic(applyLogic(config, dungeons, state));
-       }, [config, dungeons, state]);
-
-       const value = React.useMemo(() => {
-               return {
-                       addPin,
-                       config,
-                       dungeons,
-                       logic,
-                       pins,
-                       removePin,
-                       saveConfig,
-                       setAutoState,
-                       setManualState,
-                       state,
-               };
-       }, [config, dungeons, logic, pins, state]);
-
-       return <context.Provider value={value}>
-               {children}
-       </context.Provider>;
-};
-
-TrackerProvider.propTypes = {
-       children: PropTypes.node,
-};
diff --git a/resources/js/hooks/tracker.jsx b/resources/js/hooks/tracker.jsx
new file mode 100644 (file)
index 0000000..d0fb6b8
--- /dev/null
@@ -0,0 +1,87 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import {
+       CONFIG,
+       DUNGEONS,
+       applyLogic,
+       configureDungeons,
+       makeEmptyState,
+       mergeStates,
+} from '../helpers/tracker';
+
+const context = React.createContext({});
+
+export const useTracker = () => React.useContext(context);
+
+export const TrackerProvider = ({ children }) => {
+       const [config, setConfig] = React.useState(CONFIG);
+       const [state, setState] = React.useState(makeEmptyState());
+       const [autoState, setAutoState] = React.useState(makeEmptyState());
+       const [manualState, setManualState] = React.useState(makeEmptyState());
+       const [dungeons, setDungeons] = React.useState(DUNGEONS);
+       const [logic, setLogic] = React.useState({});
+       const [pins, setPins] = React.useState([]);
+
+       const saveConfig = React.useCallback((values) => {
+               setConfig(s => {
+                       const newConfig = { ...s, ...values };
+                       localStorage.setItem('tracker.config', JSON.stringify(newConfig));
+                       return newConfig;
+               });
+       }, []);
+
+       const addPin = React.useCallback((pin) => {
+               setPins(ps => {
+                       const id = ps.length ? ps[ps.length - 1].id + 1 : 1;
+                       return [...ps, { ...pin, id }];
+               });
+       }, []);
+
+       const removePin = React.useCallback((pin) => {
+               setPins(ps => ps.filter(p => p.id !== pin.id));
+       }, []);
+
+       React.useEffect(() => {
+               const savedConfig = localStorage.getItem('tracker.config');
+               if (savedConfig) {
+                       setConfig(c => ({ ...c, ...JSON.parse(savedConfig) }));
+               }
+       }, []);
+
+       React.useEffect(() => {
+               const newDungeons = configureDungeons(config);
+               setDungeons(newDungeons);
+       }, [config]);
+
+       React.useEffect(() => {
+               setState(mergeStates(autoState, manualState));
+       }, [autoState, manualState]);
+
+       React.useEffect(() => {
+               setLogic(applyLogic(config, dungeons, state));
+       }, [config, dungeons, state]);
+
+       const value = React.useMemo(() => {
+               return {
+                       addPin,
+                       config,
+                       dungeons,
+                       logic,
+                       pins,
+                       removePin,
+                       saveConfig,
+                       setAutoState,
+                       setManualState,
+                       state,
+               };
+       }, [config, dungeons, logic, pins, state]);
+
+       return <context.Provider value={value}>
+               {children}
+       </context.Provider>;
+};
+
+TrackerProvider.propTypes = {
+       children: PropTypes.node,
+};
diff --git a/resources/js/hooks/user.js b/resources/js/hooks/user.js
deleted file mode 100644 (file)
index 03173d5..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-import axios from 'axios';
-import { isEqual } from 'lodash';
-import PropTypes from 'prop-types';
-import React from 'react';
-
-const context = React.createContext({
-       login: () => false,
-       logout: () => false,
-       user: null,
-});
-
-export const useUser = () => React.useContext(context);
-
-export const withUser = (WrappedComponent, as) => function WithUserContext(props) {
-       return <context.Consumer>
-               {ctx => <WrappedComponent {...{[as || 'user']: ctx.user, ...props}} />}
-       </context.Consumer>;
-};
-
-export const UserProvider = ({ children }) => {
-       const [user, setUser] = React.useState(null);
-
-       const fetchUser = React.useCallback(async () => {
-               try {
-                       const response = await axios.get('/api/user');
-                       setUser(user => isEqual(user, response.data) ? user : response.data);
-               } catch (e) {
-                       setUser(null);
-               }
-       }, []);
-
-       React.useEffect(() => {
-               let timer = null;
-               axios
-                       .get('/sanctum/csrf-cookie')
-                       .then(() => {
-                               fetchUser();
-                               timer = setInterval(fetchUser, 5 * 60 * 1000);
-                       });
-               return () => {
-                       if (timer) clearInterval(timer);
-               };
-       }, []);
-
-       const login = React.useCallback(async (creds) => {
-               try {
-                       await axios.post('/login', {
-                               ...creds,
-                               remember: 'on',
-                       });
-                       await fetchUser();
-               } catch (error) {
-                       if (error.response && error.response.status === 419) {
-                               await axios.get('/sanctum/csrf-cookie');
-                               await axios.post('/login', {
-                                       ...creds,
-                                       remember: 'on',
-                               });
-                               await fetchUser();
-                       } else {
-                               throw error;
-                       }
-               }
-       }, []);
-
-       const logout = React.useCallback(async () => {
-               await axios.post('/logout');
-               setUser(null);
-       }, []);
-
-       return <context.Provider value={{ login, logout, user }}>
-               {children}
-       </context.Provider>;
-};
-
-UserProvider.propTypes = {
-       children: PropTypes.node,
-};
diff --git a/resources/js/hooks/user.jsx b/resources/js/hooks/user.jsx
new file mode 100644 (file)
index 0000000..03173d5
--- /dev/null
@@ -0,0 +1,78 @@
+import axios from 'axios';
+import { isEqual } from 'lodash';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+const context = React.createContext({
+       login: () => false,
+       logout: () => false,
+       user: null,
+});
+
+export const useUser = () => React.useContext(context);
+
+export const withUser = (WrappedComponent, as) => function WithUserContext(props) {
+       return <context.Consumer>
+               {ctx => <WrappedComponent {...{[as || 'user']: ctx.user, ...props}} />}
+       </context.Consumer>;
+};
+
+export const UserProvider = ({ children }) => {
+       const [user, setUser] = React.useState(null);
+
+       const fetchUser = React.useCallback(async () => {
+               try {
+                       const response = await axios.get('/api/user');
+                       setUser(user => isEqual(user, response.data) ? user : response.data);
+               } catch (e) {
+                       setUser(null);
+               }
+       }, []);
+
+       React.useEffect(() => {
+               let timer = null;
+               axios
+                       .get('/sanctum/csrf-cookie')
+                       .then(() => {
+                               fetchUser();
+                               timer = setInterval(fetchUser, 5 * 60 * 1000);
+                       });
+               return () => {
+                       if (timer) clearInterval(timer);
+               };
+       }, []);
+
+       const login = React.useCallback(async (creds) => {
+               try {
+                       await axios.post('/login', {
+                               ...creds,
+                               remember: 'on',
+                       });
+                       await fetchUser();
+               } catch (error) {
+                       if (error.response && error.response.status === 419) {
+                               await axios.get('/sanctum/csrf-cookie');
+                               await axios.post('/login', {
+                                       ...creds,
+                                       remember: 'on',
+                               });
+                               await fetchUser();
+                       } else {
+                               throw error;
+                       }
+               }
+       }, []);
+
+       const logout = React.useCallback(async () => {
+               await axios.post('/logout');
+               setUser(null);
+       }, []);
+
+       return <context.Provider value={{ login, logout, user }}>
+               {children}
+       </context.Provider>;
+};
+
+UserProvider.propTypes = {
+       children: PropTypes.node,
+};
index f2713548ab79dbc0dca5bf7136f0e562e451bcac..fc4b2952b9ebf73a4bcf1c1126a5692e997c715f 100644 (file)
@@ -66,17 +66,24 @@ export default {
                },
                button: {
                        add: 'Hinzufügen',
                },
                button: {
                        add: 'Hinzufügen',
+                       asComms: 'Als Kommentator',
+                       asCrew: 'Als Crew',
+                       asRunner: 'Als Runner',
+                       asSetup: 'Als Setup-Helper',
+                       asTracker: 'Als Tracker',
                        back: 'Zurück',
                        browserSource: 'Browser Source',
                        cancel: 'Abbrechen',
                        chart: 'Diagramm',
                        close: 'Schließen',
                        confirm: 'Bestätigen',
                        back: 'Zurück',
                        browserSource: 'Browser Source',
                        cancel: 'Abbrechen',
                        chart: 'Diagramm',
                        close: 'Schließen',
                        confirm: 'Bestätigen',
+                       delete: 'Löschen',
                        edit: 'Bearbeiten',
                        filter: 'Filter',
                        generate: 'Generieren',
                        help: 'Hilfe',
                        invert: 'Umkehren',
                        edit: 'Bearbeiten',
                        filter: 'Filter',
                        generate: 'Generieren',
                        help: 'Hilfe',
                        invert: 'Umkehren',
+                       load: 'Laden',
                        login: 'Login',
                        logout: 'Logout',
                        new: 'Neu',
                        login: 'Login',
                        logout: 'Logout',
                        new: 'Neu',
@@ -86,6 +93,7 @@ export default {
                        playPause: 'Play/Pause',
                        protocol: 'Protokoll',
                        remove: 'Entfernen',
                        playPause: 'Play/Pause',
                        protocol: 'Protokoll',
                        remove: 'Entfernen',
+                       reset: 'Zurücksetzen',
                        retry: 'Neu versuchen',
                        save: 'Speichern',
                        search: 'Suche',
                        retry: 'Neu versuchen',
                        save: 'Speichern',
                        search: 'Suche',
@@ -98,6 +106,7 @@ export default {
                        unset: 'Zurücksetzen',
                },
                chatBotLog: {
                        unset: 'Zurücksetzen',
                },
                chatBotLog: {
+                       context: 'Kontext',
                        empty: 'Noch keine Nachrichten erfasst',
                        heading: 'Chat Bot Protokoll',
                        info: {
                        empty: 'Noch keine Nachrichten erfasst',
                        heading: 'Chat Bot Protokoll',
                        info: {
@@ -108,6 +117,9 @@ export default {
                        origin: {
                                chatLog: 'Quelle: {{ nick }} in {{ channel }} am {{ date, L LT }}',
                        },
                        origin: {
                                chatLog: 'Quelle: {{ nick }} in {{ channel }} am {{ date, L LT }}',
                        },
+                       originalContext: 'Ursprünglicher Kontext',
+                       shortTimestamp: '{{ date, HH:mm:ss }}',
+                       showContext: 'Kontext zeigen',
                },
                content: {
                        attribution: 'Attribution',
                },
                content: {
                        attribution: 'Attribution',
@@ -127,11 +139,16 @@ export default {
                },
                discordBot: {
                        channel: 'Kanal',
                },
                discordBot: {
                        channel: 'Kanal',
+                       channelControls: 'Kanal-Steuerung',
                        controls: 'Steuerung',
                        guild: 'Server',
                        heading: 'Discord Bot',
                        invite: 'Bot einladen',
                        controls: 'Steuerung',
                        guild: 'Server',
                        heading: 'Discord Bot',
                        invite: 'Bot einladen',
+                       message: 'Nachricht',
+                       messageError: 'Fehler beim Senden',
+                       messageSuccess: 'Nachricht in Warteschlange',
                        selectGuild: 'Bitte Server wählen',
                        selectGuild: 'Bitte Server wählen',
+                       sendMessage: 'Nachricht senden'
                },
                episodes: {
                        addRestream: 'Neuer Restream',
                },
                episodes: {
                        addRestream: 'Neuer Restream',
@@ -183,15 +200,33 @@ export default {
                        end: 'Ende',
                        evergreen: 'Ständige Veranstaltungen',
                        heading: 'Veranstaltungen',
                        end: 'Ende',
                        evergreen: 'Ständige Veranstaltungen',
                        heading: 'Veranstaltungen',
+                       noPastEpisodes: 'Keine vergangenen Rennen gefunden.',
+                       noUpcomingEpisodes: 'Keine anstehenden Rennen gefunden.',
                        ongoing: 'Laufende Veranstaltungen',
                        past: 'Vergangene Veranstaltungen',
                        pastEpisodes: 'Vergangene Rennen',
                        ongoing: 'Laufende Veranstaltungen',
                        past: 'Vergangene Veranstaltungen',
                        pastEpisodes: 'Vergangene Rennen',
+                       setFutureMode: 'Anstehende Rennen zeigen',
+                       setPastMode: 'Vergangene Rennen zeigen',
                        start: 'Start',
                        upcomingEpisodes: 'Anstehende Rennen',
                },
                        start: 'Start',
                        upcomingEpisodes: 'Anstehende Rennen',
                },
+               front: {
+                       circus: 'Mystery Zirkus',
+                       eventlist: 'Liste der Veranstaltungen',
+                       events: 'Veranstaltungen und Restreams',
+                       map: 'ALttP Karte',
+                       resources: 'Lernmaterial',
+                       schedule: 'Race und Restream Terminplan',
+                       sdw: 'Seed der Woche',
+                       tech: 'Tricks und Tutorials',
+                       title: 'Gemischter Link to the Past und Super Metroid Krams',
+                       tournaments: 'Laufende Wettbewerbe',
+               },
                footer: {
                        alttpde: 'Deutscher ALttP Discord',
                footer: {
                        alttpde: 'Deutscher ALttP Discord',
+                       alttprasyncs: 'ALttPR Asyncs',
                        alttpwiki: 'ALttP Speedrunning Wiki',
                        alttpwiki: 'ALttP Speedrunning Wiki',
+                       circus: 'Lost Woods Community - Mystery Zirkus',
                        competitions: 'Wettbewerbe',
                        connect: 'Connect Spedruns Discord',
                        contact: 'Wenn du gerne ein Turnier auf dieser Seite organisieren möchtest, wende dich bitte an holysmoke86 im Discord.',
                        competitions: 'Wettbewerbe',
                        connect: 'Connect Spedruns Discord',
                        contact: 'Wenn du gerne ein Turnier auf dieser Seite organisieren möchtest, wende dich bitte an holysmoke86 im Discord.',
@@ -203,8 +238,11 @@ export default {
                        resources: 'Ressourcen',
                        restreamCentral: 'Restream Central Discord',
                        schedule: 'Terminplan',
                        resources: 'Ressourcen',
                        restreamCentral: 'Restream Central Discord',
                        schedule: 'Terminplan',
+                       sdw: 'Deutsche ALttP Community - Seed der Woche',
                        smd: 'Deutscher Super Metroid Discord',
                        smwiki: 'Super Metroid Speedrunning Wiki',
                        smd: 'Deutscher Super Metroid Discord',
                        smwiki: 'Super Metroid Speedrunning Wiki',
+                       smz3asyncs: 'SMZ3 Asyncs',
+                       stepladder: 'ALttPR Step Ladder',
                        tech: 'ALttP Techniken',
                },
                general: {
                        tech: 'ALttP Techniken',
                },
                general: {
@@ -212,13 +250,20 @@ export default {
                        anonymous: 'Anonym',
                        appDescription: 'Turniere und Tutorials für The Legend of Zelda: A Link to the Past Randomizer',
                        appName: 'ALttP',
                        anonymous: 'Anonym',
                        appDescription: 'Turniere und Tutorials für The Legend of Zelda: A Link to the Past Randomizer',
                        appName: 'ALttP',
-                       pleaseSelect: 'Bitte wählen',
                        languages: {
                                de: 'Deutsch',
                                en: 'Englisch',
                                es: 'Spanisch',
                                fr: 'Französisch',
                        },
                        languages: {
                                de: 'Deutsch',
                                en: 'Englisch',
                                es: 'Spanisch',
                                fr: 'Französisch',
                        },
+                       loadError: 'Fehler beim Laden',
+                       loading: 'Laden',
+                       loadSuccess: 'Geladen',
+                       pleaseSelect: 'Bitte wählen',
+                       resetError: 'Fehler beim Zurücksetzen',
+                       resetSuccess: 'Zurückgesetzt',
+                       saveError: 'Fehler beim Speichern',
+                       saveSuccess: 'Gespeichert',
                },
                icon: {
                        AddIcon: 'Hinzufügen',
                },
                icon: {
                        AddIcon: 'Hinzufügen',
@@ -363,8 +408,10 @@ export default {
                        uwShort: 'UW',
                },
                menu: {
                        uwShort: 'UW',
                },
                menu: {
+                       circus: 'Mystery Zirkus',
                        map: 'Karte',
                        schedule: 'Terminplan',
                        map: 'Karte',
                        schedule: 'Terminplan',
+                       sdw: 'Seed der Woche',
                        tech: 'Techniken',
                },
                modes: {
                        tech: 'Techniken',
                },
                modes: {
@@ -390,7 +437,7 @@ export default {
                privacy: {
                        heading: 'Datenschutz',
                        p1: 'Wir benutzen Cookies und den Browserspeicher, um deine Anmeldung und die ausgewählte Sprache zu speichern, sowie XSRF zu verhinden.',
                privacy: {
                        heading: 'Datenschutz',
                        p1: 'Wir benutzen Cookies und den Browserspeicher, um deine Anmeldung und die ausgewählte Sprache zu speichern, sowie XSRF zu verhinden.',
-                       p2: 'Wenn du auf den Login Button klickst, wirst du auf eine Anmeldeseite von Discord weitergeleitet. Sofern du dich anmeldest, überträgt Discord und deinen Benutzernamen, Discriminator und ID.',
+                       p2: 'Wenn du auf den Login Button klickst, wirst du auf eine Anmeldeseite von Discord weitergeleitet. Sofern du dich anmeldest, überträgt Discord uns deinen Benutzernamen, Discriminator und ID.',
                        p3: 'Deine Eingaben bei Turnieren werden als Teil des Ergebnisses auf dieser Seite veröffenlicht und ggf. auf dem Discord-Server der entsprechenden Community geteilt.',
                },
                protocol: {
                        p3: 'Deine Eingaben bei Turnieren werden als Teil des Ergebnisses auf dieser Seite veröffenlicht und ggf. auf dem Discord-Server der entsprechenden Community geteilt.',
                },
                protocol: {
@@ -406,6 +453,7 @@ export default {
                                },
                                round: {
                                        create: 'Runde #{{number}} hinzugefügt',
                                },
                                round: {
                                        create: 'Runde #{{number}} hinzugefügt',
+                                       delete: 'Runde #{{number}} gelöscht',
                                        edit: 'Runde #{{number}} bearbeitet',
                                        lock: 'Runde #{{number}} gesperrt',
                                        seed: 'Seed für Runde #{{number}} eingetragen',
                                        edit: 'Runde #{{number}} bearbeitet',
                                        lock: 'Runde #{{number}} gesperrt',
                                        seed: 'Seed für Runde #{{number}} eingetragen',
@@ -450,6 +498,10 @@ export default {
                rounds: {
                        code: 'Code',
                        date: '{{ date, L }}',
                rounds: {
                        code: 'Code',
                        date: '{{ date, L }}',
+                       delete: 'Runde löschen',
+                       deleteConfirmMessage: 'Runde #{{ number }} vom {{ date, L }} löschen?',
+                       deleteError: 'Fehler beim Löschen',
+                       deleteSuccess: 'Runde gelöscht',
                        edit: 'Runde bearbeiten',
                        editError: 'Fehler beim Speichern',
                        editSuccess: 'Gespeichert',
                        edit: 'Runde bearbeiten',
                        editError: 'Fehler beim Speichern',
                        editSuccess: 'Gespeichert',
@@ -684,6 +736,20 @@ export default {
                        open: 'Anmeldung geöffnet',
                        openError: 'Fehler beim Öffnen der Anmledung',
                        openSuccess: 'Anmeldung geöffnet',
                        open: 'Anmeldung geöffnet',
                        openError: 'Fehler beim Öffnen der Anmledung',
                        openSuccess: 'Anmeldung geöffnet',
+                       resultReveal: 'Frühzeitige Ergebnisse',
+                       resultRevealDescription: 'Ob und wann Ergebnisse von offenen Runden angezeigt werden sollen.',
+                       resultRevealOption: {
+                               always: 'Immer',
+                               finishers: 'Absolventen',
+                               never: 'Nie',
+                               participants: 'Teilnehmern',
+                       },
+                       resultRevealOptionDescription: {
+                               always: 'Ergebnis wird allen angezeigt, sobald es eingetragen wird.',
+                               finishers: 'Ergebnis wird allen Teilnehmern angezeigt, die eine Zeit (oder DNF) für die Runde eingetragen haben.',
+                               never: 'Ergebnis wird erst mit Abschluss der Runde veröffentlicht.',
+                               participants: 'Ergebnis wird allen registrierten Teilnehmern des Turniers angezeigt.',
+                       },
                        scoreboard: 'Scoreboard',
                        scoreChart: 'Turnierverlauf',
                        settings: 'Einstellungen',
                        scoreboard: 'Scoreboard',
                        scoreChart: 'Turnierverlauf',
                        settings: 'Einstellungen',
@@ -712,6 +778,7 @@ export default {
                                lol: 'Gelächter',
                                love: 'Love',
                                no: 'Nein',
                                lol: 'Gelächter',
                                love: 'Love',
                                no: 'Nein',
+                               number: 'Zahl',
                                o7: 'Salutieren',
                                pog: 'Pog',
                                question: 'Frage',
                                o7: 'Salutieren',
                                pog: 'Pog',
                                question: 'Frage',
@@ -723,6 +790,7 @@ export default {
                                wtf: 'WTF',
                                yes: 'Ja',
                        },
                                wtf: 'WTF',
                                yes: 'Ja',
                        },
+                       chatChannels: 'Aktive Channel',
                        chatError: 'Fehler beim Senden',
                        chatMinAge: 'Mindestalter (in Tagen)',
                        chatSettings: 'Chat Bot Einstellungen',
                        chatError: 'Fehler beim Senden',
                        chatMinAge: 'Mindestalter (in Tagen)',
                        chatSettings: 'Chat Bot Einstellungen',
@@ -833,6 +901,7 @@ export default {
                        discordTag: 'Discord Tag',
                        editNickname: 'Name bearbeiten',
                        editStreamLink: 'Stream Link bearbeiten',
                        discordTag: 'Discord Tag',
                        editNickname: 'Name bearbeiten',
                        editStreamLink: 'Stream Link bearbeiten',
+                       episodes: 'Restreams',
                        nickname: 'Name',
                        noStream: 'Kein Stream gesetzt',
                        participationEmpty: 'Hat noch an keinen Turnieren teilgenommen.',
                        nickname: 'Name',
                        noStream: 'Kein Stream gesetzt',
                        participationEmpty: 'Hat noch an keinen Turnieren teilgenommen.',
index 8d8ccdce56b3983d5c3cf380cb04727aeef8fd09..b2175c5cc10d6b815b5b08a4a92e06e34d7e9943 100644 (file)
@@ -66,17 +66,24 @@ export default {
                },
                button: {
                        add: 'Add',
                },
                button: {
                        add: 'Add',
+                       asComms: 'As Commentary',
+                       asCrew: 'As Crew',
+                       asRunner: 'As Runner',
+                       asSetup: 'As Setup Helper',
+                       asTracker: 'As Tracker',
                        back: 'Back',
                        browserSource: 'Browser source',
                        cancel: 'Cancel',
                        chart: 'Chart',
                        close: 'Close',
                        confirm: 'Confirm',
                        back: 'Back',
                        browserSource: 'Browser source',
                        cancel: 'Cancel',
                        chart: 'Chart',
                        close: 'Close',
                        confirm: 'Confirm',
+                       delete: 'Delete',
                        edit: 'Edit',
                        filter: 'Filter',
                        generate: 'Generate',
                        help: 'Help',
                        invert: 'Invert',
                        edit: 'Edit',
                        filter: 'Filter',
                        generate: 'Generate',
                        help: 'Help',
                        invert: 'Invert',
+                       load: 'Load',
                        login: 'Login',
                        logout: 'Logout',
                        new: 'New',
                        login: 'Login',
                        logout: 'Logout',
                        new: 'New',
@@ -86,6 +93,7 @@ export default {
                        playPause: 'Play/Pause',
                        protocol: 'Protocol',
                        remove: 'Remove',
                        playPause: 'Play/Pause',
                        protocol: 'Protocol',
                        remove: 'Remove',
+                       reset: 'Reset',
                        retry: 'Retry',
                        save: 'Save',
                        search: 'Search',
                        retry: 'Retry',
                        save: 'Save',
                        search: 'Search',
@@ -98,6 +106,7 @@ export default {
                        unset: 'Unset',
                },
                chatBotLog: {
                        unset: 'Unset',
                },
                chatBotLog: {
+                       context: 'Context',
                        empty: 'No messages on protocol yet',
                        heading: 'Chat Bot Log',
                        info: {
                        empty: 'No messages on protocol yet',
                        heading: 'Chat Bot Log',
                        info: {
@@ -108,6 +117,9 @@ export default {
                        origin: {
                                chatLog: 'Source: {{ nick }} in {{ channel }} on {{ date, L LT }}',
                        },
                        origin: {
                                chatLog: 'Source: {{ nick }} in {{ channel }} on {{ date, L LT }}',
                        },
+                       originalContext: 'Original context',
+                       shortTimestamp: '{{ date, hh:mm:ss }}',
+                       showContext: 'Show context',
                },
                content: {
                        attribution: 'Attribution',
                },
                content: {
                        attribution: 'Attribution',
@@ -127,11 +139,16 @@ export default {
                },
                discordBot: {
                        channel: 'Channel',
                },
                discordBot: {
                        channel: 'Channel',
+                       channelControls: 'Channel controls',
                        controls: 'Controls',
                        guild: 'Server',
                        heading: 'Discord Bot',
                        invite: 'Invite bot',
                        controls: 'Controls',
                        guild: 'Server',
                        heading: 'Discord Bot',
                        invite: 'Invite bot',
+                       message: 'Message',
+                       messageError: 'Error sending message',
+                       messageSuccess: 'Message queued',
                        selectGuild: 'Please select server',
                        selectGuild: 'Please select server',
+                       sendMessage: 'Send message',
                },
                episodes: {
                        addRestream: 'Add Restream',
                },
                episodes: {
                        addRestream: 'Add Restream',
@@ -183,15 +200,33 @@ export default {
                        end: 'End',
                        evergreen: 'Evergreen events',
                        heading: 'Events',
                        end: 'End',
                        evergreen: 'Evergreen events',
                        heading: 'Events',
+                       noPastEpisodes: 'No past races found.',
+                       noUpcomingEpisodes: 'No upcoming races found.',
                        ongoing: 'Ongoing events',
                        past: 'Past events',
                        pastEpisodes: 'Past races',
                        ongoing: 'Ongoing events',
                        past: 'Past events',
                        pastEpisodes: 'Past races',
+                       setFutureMode: 'Show upcoming races',
+                       setPastMode: 'Show past races',
                        start: 'Start',
                        upcomingEpisodes: 'Upcoming races',
                },
                        start: 'Start',
                        upcomingEpisodes: 'Upcoming races',
                },
+               front: {
+                       circus: 'Mystery Circus',
+                       eventlist: 'List of Events',
+                       events: 'Events and Restreams',
+                       map: 'ALttP Map',
+                       resources: 'Learning Resources',
+                       schedule: 'Schedule of Races and Restreams',
+                       sdw: 'Seed of the Week',
+                       tech: 'Tech and Tutorials',
+                       title: 'Various Link to the Past and Super Metroid Stuff',
+                       tournaments: 'Active Competitions',
+               },
                footer: {
                        alttpde: 'German ALttP Discord',
                footer: {
                        alttpde: 'German ALttP Discord',
+                       alttprasyncs: 'ALttPR Asyncs',
                        alttpwiki: 'ALttP Speedrunning Wiki',
                        alttpwiki: 'ALttP Speedrunning Wiki',
+                       circus: 'Lost Woods Community - Mystery Circus',
                        competitions: 'Competitions',
                        connect: 'Connect Spedruns Discord',
                        contact: 'If you would like to organize a Tournament on this site, please contact holysmoke86 on Discord.',
                        competitions: 'Competitions',
                        connect: 'Connect Spedruns Discord',
                        contact: 'If you would like to organize a Tournament on this site, please contact holysmoke86 on Discord.',
@@ -203,8 +238,11 @@ export default {
                        resources: 'Resources',
                        restreamCentral: 'Restream Central Discord',
                        schedule: 'Schedule',
                        resources: 'Resources',
                        restreamCentral: 'Restream Central Discord',
                        schedule: 'Schedule',
+                       sdw: 'German ALttP Community - Seed of the Week',
                        smd: 'German Super Metroid Discord',
                        smwiki: 'Super Metroid Speedrunning Wiki',
                        smd: 'German Super Metroid Discord',
                        smwiki: 'Super Metroid Speedrunning Wiki',
+                       smz3asyncs: 'SMZ3 Asyncs',
+                       stepladder: 'ALttPR Step Ladder',
                        tech: 'ALttP Tech',
                },
                general: {
                        tech: 'ALttP Tech',
                },
                general: {
@@ -212,13 +250,20 @@ export default {
                        anonymous: 'Anonym',
                        appDescription: 'Tournaments and tutorials for The Legend of Zelda: A Link to the Past Randomizer',
                        appName: 'ALttP',
                        anonymous: 'Anonym',
                        appDescription: 'Tournaments and tutorials for The Legend of Zelda: A Link to the Past Randomizer',
                        appName: 'ALttP',
-                       pleaseSelect: 'Please select',
                        languages: {
                                de: 'German',
                                en: 'English',
                                es: 'Spanish',
                                fr: 'French',
                        },
                        languages: {
                                de: 'German',
                                en: 'English',
                                es: 'Spanish',
                                fr: 'French',
                        },
+                       loadError: 'Error loading',
+                       loading: 'Loading',
+                       loadSuccess: 'Loading successful',
+                       pleaseSelect: 'Please select',
+                       resetError: 'Error resetting',
+                       resetSuccess: 'Reset successful',
+                       saveError: 'Error saving',
+                       saveSuccess: 'Saved successfully',
                },
                icon: {
                        AddIcon: 'Add',
                },
                icon: {
                        AddIcon: 'Add',
@@ -363,8 +408,10 @@ export default {
                        uwShort: 'UW',
                },
                menu: {
                        uwShort: 'UW',
                },
                menu: {
+                       circus: 'Mystery Circus',
                        map: 'Map',
                        schedule: 'Schedule',
                        map: 'Map',
                        schedule: 'Schedule',
+                       sdw: 'Seed of the Week',
                        tech: 'Tech',
                },
                modes: {
                        tech: 'Tech',
                },
                modes: {
@@ -406,6 +453,7 @@ export default {
                                },
                                round: {
                                        create: 'Added round #{{number}}',
                                },
                                round: {
                                        create: 'Added round #{{number}}',
+                                       delete: 'Deleted round #{{number}}',
                                        edit: 'Edited round #{{number}}',
                                        lock: 'Round #{{number}} locked',
                                        seed: 'Set seed for round #{{number}}',
                                        edit: 'Edited round #{{number}}',
                                        lock: 'Round #{{number}} locked',
                                        seed: 'Set seed for round #{{number}}',
@@ -450,6 +498,10 @@ export default {
                rounds: {
                        code: 'Code',
                        date: '{{ date, L }}',
                rounds: {
                        code: 'Code',
                        date: '{{ date, L }}',
+                       delete: 'Delete round',
+                       deleteConfirmMessage: 'Remove round #{{ number }} from {{ date, L }}?',
+                       deleteError: 'Error deleting round',
+                       deleteSuccess: 'Round deleted',
                        edit: 'Edit round',
                        editError: 'Error saving round',
                        editSuccess: 'Saved successfully',
                        edit: 'Edit round',
                        editError: 'Error saving round',
                        editSuccess: 'Saved successfully',
@@ -684,6 +736,20 @@ export default {
                        open: 'Open registration',
                        openError: 'Error opening registration',
                        openSuccess: 'Registration opened',
                        open: 'Open registration',
                        openError: 'Error opening registration',
                        openSuccess: 'Registration opened',
+                       resultReveal: 'Early results',
+                       resultRevealDescription: 'When to show results for open rounds.',
+                       resultRevealOption: {
+                               always: 'Always',
+                               finishers: 'Finishers',
+                               never: 'Never',
+                               participants: 'Participants',
+                       },
+                       resultRevealOptionDescription: {
+                               always: 'Show all results as they come in.',
+                               finishers: 'Show results to participants who submitted a time (or DNF).',
+                               never: 'Only reveal results once the round has closed down.',
+                               participants: 'Show results to only registered tournament members.',
+                       },
                        scoreboard: 'Scoreboard',
                        scoreChart: 'Score chart',
                        settings: 'Settings',
                        scoreboard: 'Scoreboard',
                        scoreChart: 'Score chart',
                        settings: 'Settings',
@@ -712,6 +778,7 @@ export default {
                                lol: 'Laughter',
                                love: 'Love',
                                no: 'No',
                                lol: 'Laughter',
                                love: 'Love',
                                no: 'No',
+                               number: 'Number',
                                o7: 'Salute',
                                pog: 'Pog',
                                question: 'Question',
                                o7: 'Salute',
                                pog: 'Pog',
                                question: 'Question',
@@ -723,6 +790,7 @@ export default {
                                wtf: 'WTF',
                                yes: 'Yes',
                        },
                                wtf: 'WTF',
                                yes: 'Yes',
                        },
+                       chatChannels: 'Active Channels',
                        chatError: 'Error sending message',
                        chatMinAge: 'Min. age (in days)',
                        chatSettings: 'Chat Bot Settings',
                        chatError: 'Error sending message',
                        chatMinAge: 'Min. age (in days)',
                        chatSettings: 'Chat Bot Settings',
@@ -833,6 +901,7 @@ export default {
                        discordTag: 'Discord tag',
                        editNickname: 'Edit name',
                        editStreamLink: 'Edit stream link',
                        discordTag: 'Discord tag',
                        editNickname: 'Edit name',
                        editStreamLink: 'Edit stream link',
+                       episodes: 'Restreams',
                        nickname: 'Name',
                        noStream: 'No stream set',
                        participationEmpty: 'Has not participated in any tourneys yet.',
                        nickname: 'Name',
                        noStream: 'No stream set',
                        participationEmpty: 'Has not participated in any tourneys yet.',
index 63803cd4c31b7dd3f6570085951ca22f85aa1539..0138bdfa2b3092e79920e830ebb8e3c96f0a0176 100644 (file)
@@ -7,7 +7,7 @@ import { initReactI18next } from 'react-i18next';
 import de from './de';
 import en from './en';
 import 'numeral/locales/de';
 import de from './de';
 import en from './en';
 import 'numeral/locales/de';
-import 'moment/locale/de';
+import 'moment/dist/locale/de';
 
 const supportedLocales = [
        'de',
 
 const supportedLocales = [
        'de',
diff --git a/resources/js/index.js b/resources/js/index.js
deleted file mode 100644 (file)
index f4cda61..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * First we will load all of this project's JavaScript dependencies which
- * includes React and other helpers. It's a great starting point while
- * building robust, powerful web applications using React + Laravel.
- */
-
-import './bootstrap';
-
-import React from 'react';
-import { createRoot } from 'react-dom/client';
-
-import toastr from 'toastr';
-toastr.options.positionClass = 'toast-bottom-right';
-
-/**
- * Next, we will create a fresh React component instance and attach it to
- * the page. Then, you may begin adding components to this application
- * or customize the JavaScript scaffolding to fit your unique needs.
- */
-
-import App from './app';
-
-if (document.getElementById('react-root')) {
-       const root = createRoot(document.getElementById('react-root'));
-       root.render(<App />);
-}
diff --git a/resources/js/index.jsx b/resources/js/index.jsx
new file mode 100644 (file)
index 0000000..f44ece7
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * First we will load all of this project's JavaScript dependencies which
+ * includes React and other helpers. It's a great starting point while
+ * building robust, powerful web applications using React + Laravel.
+ */
+
+import './bootstrap';
+import '../sass/app.scss';
+
+import React from 'react';
+import { createRoot } from 'react-dom/client';
+
+import toastr from 'toastr';
+toastr.options.positionClass = 'toast-bottom-right';
+
+/**
+ * Next, we will create a fresh React component instance and attach it to
+ * the page. Then, you may begin adding components to this application
+ * or customize the JavaScript scaffolding to fit your unique needs.
+ */
+
+import App from './app';
+
+if (document.getElementById('react-root')) {
+       const root = createRoot(document.getElementById('react-root'));
+       root.render(<App />);
+}
diff --git a/resources/js/pages/AlttpSeed.js b/resources/js/pages/AlttpSeed.js
deleted file mode 100644 (file)
index 74769d8..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-import axios from 'axios';
-import React, { useCallback, useEffect, useState } from 'react';
-import { Helmet } from 'react-helmet';
-import { useParams } from 'react-router-dom';
-
-import NotFound from './NotFound';
-import Seed from '../components/alttp-seeds/Seed';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import ErrorMessage from '../components/common/ErrorMessage';
-import Loading from '../components/common/Loading';
-
-export const Component = () => {
-       const params = useParams();
-       const { hash } = params;
-
-       const [error, setError] = useState(null);
-       const [loading, setLoading] = useState(true);
-       const [patch, setPatch] = useState(null);
-       const [seed, setSeed] = useState(null);
-
-       const loadSeed = useCallback((hash, ctrl) => {
-               axios
-                       .get(`/api/alttp-seed/${hash}`, { signal: ctrl.signal })
-                       .then(response => {
-                               setError(null);
-                               setLoading(false);
-                               setSeed(response.data);
-                       })
-                       .catch(error => {
-                               setError(error);
-                               setLoading(false);
-                               setSeed(null);
-                       });
-       }, []);
-
-       useEffect(() => {
-               setLoading(true);
-               const ctrl = new AbortController();
-               loadSeed(hash, ctrl);
-               return () => {
-                       ctrl.abort();
-               };
-       }, [hash]);
-
-       useEffect(() => {
-               if (!seed || seed.status !== 'pending') {
-                       return;
-               }
-               const ctrl = new AbortController();
-               const timer = setTimeout(() => {
-                       loadSeed(seed.hash, ctrl);
-               }, 2000);
-               return () => {
-                       clearTimeout(timer);
-                       ctrl.abort();
-               };
-       }, [seed]);
-
-       useEffect(() => {
-               setPatch(null);
-               if (!seed || seed.status !== 'generated') {
-                       return;
-               }
-               const ctrl = new AbortController();
-               axios
-                       .get(`/alttp-seeds/${hash}.bps`, {
-                               responseType: 'arraybuffer',
-                               signal: ctrl.signal,
-                       })
-                       .then(response => {
-                               setPatch(response.data);
-                       })
-                       .catch(error => {
-                               setError(error);
-                       });
-               return () => {
-                       ctrl.abort();
-               };
-       }, [hash, seed]);
-
-       const retry = useCallback(async () => {
-               await axios.post(`/api/alttp-seed/${hash}/retry`);
-               setSeed(seed => ({ ...seed, status: 'pending' }));
-       });
-
-       if (loading) {
-               return <Loading />;
-       }
-
-       if (error) {
-               return <ErrorMessage error={error} />;
-       }
-
-       if (!seed) {
-               return <NotFound />;
-       }
-
-       return <ErrorBoundary>
-               <Helmet>
-                       {seed ?
-                               <title>{seed.hash}</title>
-                       : null}
-               </Helmet>
-               <Seed onRetry={retry} patch={patch} seed={seed} />
-       </ErrorBoundary>;
-};
diff --git a/resources/js/pages/AlttpSeed.jsx b/resources/js/pages/AlttpSeed.jsx
new file mode 100644 (file)
index 0000000..74769d8
--- /dev/null
@@ -0,0 +1,106 @@
+import axios from 'axios';
+import React, { useCallback, useEffect, useState } from 'react';
+import { Helmet } from 'react-helmet';
+import { useParams } from 'react-router-dom';
+
+import NotFound from './NotFound';
+import Seed from '../components/alttp-seeds/Seed';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+
+export const Component = () => {
+       const params = useParams();
+       const { hash } = params;
+
+       const [error, setError] = useState(null);
+       const [loading, setLoading] = useState(true);
+       const [patch, setPatch] = useState(null);
+       const [seed, setSeed] = useState(null);
+
+       const loadSeed = useCallback((hash, ctrl) => {
+               axios
+                       .get(`/api/alttp-seed/${hash}`, { signal: ctrl.signal })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setSeed(response.data);
+                       })
+                       .catch(error => {
+                               setError(error);
+                               setLoading(false);
+                               setSeed(null);
+                       });
+       }, []);
+
+       useEffect(() => {
+               setLoading(true);
+               const ctrl = new AbortController();
+               loadSeed(hash, ctrl);
+               return () => {
+                       ctrl.abort();
+               };
+       }, [hash]);
+
+       useEffect(() => {
+               if (!seed || seed.status !== 'pending') {
+                       return;
+               }
+               const ctrl = new AbortController();
+               const timer = setTimeout(() => {
+                       loadSeed(seed.hash, ctrl);
+               }, 2000);
+               return () => {
+                       clearTimeout(timer);
+                       ctrl.abort();
+               };
+       }, [seed]);
+
+       useEffect(() => {
+               setPatch(null);
+               if (!seed || seed.status !== 'generated') {
+                       return;
+               }
+               const ctrl = new AbortController();
+               axios
+                       .get(`/alttp-seeds/${hash}.bps`, {
+                               responseType: 'arraybuffer',
+                               signal: ctrl.signal,
+                       })
+                       .then(response => {
+                               setPatch(response.data);
+                       })
+                       .catch(error => {
+                               setError(error);
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [hash, seed]);
+
+       const retry = useCallback(async () => {
+               await axios.post(`/api/alttp-seed/${hash}/retry`);
+               setSeed(seed => ({ ...seed, status: 'pending' }));
+       });
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       if (!seed) {
+               return <NotFound />;
+       }
+
+       return <ErrorBoundary>
+               <Helmet>
+                       {seed ?
+                               <title>{seed.hash}</title>
+                       : null}
+               </Helmet>
+               <Seed onRetry={retry} patch={patch} seed={seed} />
+       </ErrorBoundary>;
+};
diff --git a/resources/js/pages/DiscordBot.js b/resources/js/pages/DiscordBot.js
deleted file mode 100644 (file)
index 0e1d2d1..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import { Button, Container } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-
-import Icon from '../components/common/Icon';
-import Controls from '../components/discord-bot/Controls';
-
-const authEndpoint = 'https://discord.com/oauth2/authorize';
-const clientId = process.env.MIX_DISCORD_CLIENT_ID;
-
-export const Component = () => {
-       const { t } = useTranslation();
-
-       return <Container>
-               <h1>{t('discordBot.heading')}</h1>
-               <Helmet>
-                       <title>{t('discordBot.heading')}</title>
-               </Helmet>
-               <p>
-                       <span className="button-bar">
-                               <Button
-                                       href={`${authEndpoint}?client_id=${clientId}&scope=bot%20applications.commands`}
-                                       target="_blank"
-                                       variant="discord"
-                               >
-                                       <Icon.DISCORD title="" />
-                                       {' '}
-                                       {t('discordBot.invite')}
-                               </Button>
-                       </span>
-               </p>
-               <h2>{t('discordBot.controls')}</h2>
-               <Controls />
-       </Container>;
-};
diff --git a/resources/js/pages/DiscordBot.jsx b/resources/js/pages/DiscordBot.jsx
new file mode 100644 (file)
index 0000000..111cbbe
--- /dev/null
@@ -0,0 +1,36 @@
+import React from 'react';
+import { Button, Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+
+import Icon from '../components/common/Icon';
+import Controls from '../components/discord-bot/Controls';
+
+const authEndpoint = 'https://discord.com/oauth2/authorize';
+const clientId = import.meta.env.VITE_DISCORD_CLIENT_ID;
+
+export const Component = () => {
+       const { t } = useTranslation();
+
+       return <Container>
+               <h1>{t('discordBot.heading')}</h1>
+               <Helmet>
+                       <title>{t('discordBot.heading')}</title>
+               </Helmet>
+               <p>
+                       <span className="button-bar">
+                               <Button
+                                       href={`${authEndpoint}?client_id=${clientId}&scope=bot%20applications.commands`}
+                                       target="_blank"
+                                       variant="discord"
+                               >
+                                       <Icon.DISCORD title="" />
+                                       {' '}
+                                       {t('discordBot.invite')}
+                               </Button>
+                       </span>
+               </p>
+               <h2>{t('discordBot.controls')}</h2>
+               <Controls />
+       </Container>;
+};
diff --git a/resources/js/pages/DoorsTracker.js b/resources/js/pages/DoorsTracker.js
deleted file mode 100644 (file)
index 087a249..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-import React from 'react';
-import { Helmet } from 'react-helmet';
-
-import ZeldaIcon from '../components/common/ZeldaIcon';
-
-const DUNGEONS = [
-       'hc',
-       'ct',
-       'ep',
-       'dp',
-       'th',
-       'pd',
-       'sp',
-       'sw',
-       'tt',
-       'ip',
-       'mm',
-       'tr',
-       'gt',
-];
-
-const ITEMS = [
-       'compass',
-       'map',
-       'big-key',
-       'bow',
-       'hookshot',
-       'fire-rod',
-       'lamp',
-       'hammer',
-       'somaria',
-       'fighter-sword',
-       'boots',
-       'glove',
-       'flippers',
-];
-
-const ITEM_CLASSES = {
-       'compass': 'dungeon-item',
-       'map': 'dungeon-item',
-       'big-key': 'dungeon-item',
-       'bow': 'item',
-       'hookshot': 'item',
-       'fire-rod': 'item',
-       'lamp': 'item',
-       'hammer': 'item',
-       'somaria': 'item',
-       'fighter-sword': 'item',
-       'boots': 'item',
-       'glove': 'item',
-       'flippers': 'item',
-};
-
-const nextCSwitch = cur => {
-       switch (cur) {
-               case 'blue':
-                       return 'red';
-               case 'red':
-                       return '';
-               default:
-                       return 'blue';
-       }
-};
-
-const prevCSwitch = cur => nextCSwitch(nextCSwitch(cur));
-
-export const Component = () => {
-       const [state, setState] = React.useState(DUNGEONS.reduce((state, dungeon) => ({
-               ...state,
-               [dungeon]: ITEMS.reduce((items, item) => ({
-                       ...items,
-                       [item]: false,
-               }), {
-                       boss: true,
-                       cswitch: '',
-                       keys: 1,
-               }),
-       }), {}));
-
-       const handleItemClick = React.useCallback((dungeon, item) => e => {
-               setState(state => ({
-                       ...state,
-                       [dungeon]: {
-                               ...state[dungeon],
-                               [item]: !state[dungeon][item],
-                       },
-               }));
-               e.preventDefault();
-               e.stopPropagation();
-       });
-
-       const handleCSwitchClick = React.useCallback(dungeon => e => {
-               setState(state => ({
-                       ...state,
-                       [dungeon]: {
-                               ...state[dungeon],
-                               cswitch: nextCSwitch(state[dungeon].cswitch),
-                       },
-               }));
-               e.preventDefault();
-               e.stopPropagation();
-       });
-
-       const handleCSwitchRightClick = React.useCallback(dungeon => e => {
-               setState(state => ({
-                       ...state,
-                       [dungeon]: {
-                               ...state[dungeon],
-                               cswitch: prevCSwitch(state[dungeon].cswitch),
-                       },
-               }));
-               e.preventDefault();
-               e.stopPropagation();
-       });
-
-       const handleKeysClick = React.useCallback(dungeon => e => {
-               setState(state => ({
-                       ...state,
-                       [dungeon]: {
-                               ...state[dungeon],
-                               keys: state[dungeon].keys + 1,
-                       },
-               }));
-               e.preventDefault();
-               e.stopPropagation();
-       });
-
-       const handleKeysRightClick = React.useCallback(dungeon => e => {
-               setState(state => ({
-                       ...state,
-                       [dungeon]: {
-                               ...state[dungeon],
-                               keys: Math.max(state[dungeon].keys - 1, 0),
-                       },
-               }));
-               e.preventDefault();
-               e.stopPropagation();
-       });
-
-       return <>
-               <Helmet>
-                       <title>Doors Tracker</title>
-                       <meta name="description" content="Doors Tracker" />
-               </Helmet>
-               <div className="doors-tracker d-flex flex-column">
-                       {DUNGEONS.map(dungeon =>
-                               <div className="d-flex flex-row" key={dungeon}>
-                                       <div
-                                               className={`cell ${state[dungeon].boss ? 'on' : 'off'} dungeon`}
-                                               onClick={handleItemClick(dungeon, 'boss')}
-                                       >
-                                               <ZeldaIcon name={`dungeon-${dungeon}`} />
-                                       </div>
-                                       <div
-                                               className={`cell ${state[dungeon].keys ? 'on' : 'off'} keys`}
-                                               onClick={handleKeysClick(dungeon)}
-                                               onContextMenu={handleKeysRightClick(dungeon)}
-                                       >
-                                               {state[dungeon].keys}
-                                       </div>
-                                       <div
-                                               className={`cell ${state[dungeon].cswitch ? 'on' : 'off'} cswitch`}
-                                               onClick={handleCSwitchClick(dungeon)}
-                                               onContextMenu={handleCSwitchRightClick(dungeon)}
-                                       >
-                                               <ZeldaIcon name={state[dungeon].cswitch
-                                                       ? `crystal-switch-${state[dungeon].cswitch}`
-                                                       : 'crystal-switch'
-                                               } />
-                                       </div>
-                                       {ITEMS.map(item =>
-                                               <div
-                                                       className={
-                                                               `cell ${state[dungeon][item] ? 'on' : 'off'} ${ITEM_CLASSES[item]}`
-                                                       }
-                                                       key={item}
-                                                       onClick={handleItemClick(dungeon, item)}
-                                               >
-                                                       <ZeldaIcon name={item} />
-                                               </div>
-                                       )}
-                               </div>
-                       )}
-               </div>
-       </>;
-};
diff --git a/resources/js/pages/DoorsTracker.jsx b/resources/js/pages/DoorsTracker.jsx
new file mode 100644 (file)
index 0000000..087a249
--- /dev/null
@@ -0,0 +1,186 @@
+import React from 'react';
+import { Helmet } from 'react-helmet';
+
+import ZeldaIcon from '../components/common/ZeldaIcon';
+
+const DUNGEONS = [
+       'hc',
+       'ct',
+       'ep',
+       'dp',
+       'th',
+       'pd',
+       'sp',
+       'sw',
+       'tt',
+       'ip',
+       'mm',
+       'tr',
+       'gt',
+];
+
+const ITEMS = [
+       'compass',
+       'map',
+       'big-key',
+       'bow',
+       'hookshot',
+       'fire-rod',
+       'lamp',
+       'hammer',
+       'somaria',
+       'fighter-sword',
+       'boots',
+       'glove',
+       'flippers',
+];
+
+const ITEM_CLASSES = {
+       'compass': 'dungeon-item',
+       'map': 'dungeon-item',
+       'big-key': 'dungeon-item',
+       'bow': 'item',
+       'hookshot': 'item',
+       'fire-rod': 'item',
+       'lamp': 'item',
+       'hammer': 'item',
+       'somaria': 'item',
+       'fighter-sword': 'item',
+       'boots': 'item',
+       'glove': 'item',
+       'flippers': 'item',
+};
+
+const nextCSwitch = cur => {
+       switch (cur) {
+               case 'blue':
+                       return 'red';
+               case 'red':
+                       return '';
+               default:
+                       return 'blue';
+       }
+};
+
+const prevCSwitch = cur => nextCSwitch(nextCSwitch(cur));
+
+export const Component = () => {
+       const [state, setState] = React.useState(DUNGEONS.reduce((state, dungeon) => ({
+               ...state,
+               [dungeon]: ITEMS.reduce((items, item) => ({
+                       ...items,
+                       [item]: false,
+               }), {
+                       boss: true,
+                       cswitch: '',
+                       keys: 1,
+               }),
+       }), {}));
+
+       const handleItemClick = React.useCallback((dungeon, item) => e => {
+               setState(state => ({
+                       ...state,
+                       [dungeon]: {
+                               ...state[dungeon],
+                               [item]: !state[dungeon][item],
+                       },
+               }));
+               e.preventDefault();
+               e.stopPropagation();
+       });
+
+       const handleCSwitchClick = React.useCallback(dungeon => e => {
+               setState(state => ({
+                       ...state,
+                       [dungeon]: {
+                               ...state[dungeon],
+                               cswitch: nextCSwitch(state[dungeon].cswitch),
+                       },
+               }));
+               e.preventDefault();
+               e.stopPropagation();
+       });
+
+       const handleCSwitchRightClick = React.useCallback(dungeon => e => {
+               setState(state => ({
+                       ...state,
+                       [dungeon]: {
+                               ...state[dungeon],
+                               cswitch: prevCSwitch(state[dungeon].cswitch),
+                       },
+               }));
+               e.preventDefault();
+               e.stopPropagation();
+       });
+
+       const handleKeysClick = React.useCallback(dungeon => e => {
+               setState(state => ({
+                       ...state,
+                       [dungeon]: {
+                               ...state[dungeon],
+                               keys: state[dungeon].keys + 1,
+                       },
+               }));
+               e.preventDefault();
+               e.stopPropagation();
+       });
+
+       const handleKeysRightClick = React.useCallback(dungeon => e => {
+               setState(state => ({
+                       ...state,
+                       [dungeon]: {
+                               ...state[dungeon],
+                               keys: Math.max(state[dungeon].keys - 1, 0),
+                       },
+               }));
+               e.preventDefault();
+               e.stopPropagation();
+       });
+
+       return <>
+               <Helmet>
+                       <title>Doors Tracker</title>
+                       <meta name="description" content="Doors Tracker" />
+               </Helmet>
+               <div className="doors-tracker d-flex flex-column">
+                       {DUNGEONS.map(dungeon =>
+                               <div className="d-flex flex-row" key={dungeon}>
+                                       <div
+                                               className={`cell ${state[dungeon].boss ? 'on' : 'off'} dungeon`}
+                                               onClick={handleItemClick(dungeon, 'boss')}
+                                       >
+                                               <ZeldaIcon name={`dungeon-${dungeon}`} />
+                                       </div>
+                                       <div
+                                               className={`cell ${state[dungeon].keys ? 'on' : 'off'} keys`}
+                                               onClick={handleKeysClick(dungeon)}
+                                               onContextMenu={handleKeysRightClick(dungeon)}
+                                       >
+                                               {state[dungeon].keys}
+                                       </div>
+                                       <div
+                                               className={`cell ${state[dungeon].cswitch ? 'on' : 'off'} cswitch`}
+                                               onClick={handleCSwitchClick(dungeon)}
+                                               onContextMenu={handleCSwitchRightClick(dungeon)}
+                                       >
+                                               <ZeldaIcon name={state[dungeon].cswitch
+                                                       ? `crystal-switch-${state[dungeon].cswitch}`
+                                                       : 'crystal-switch'
+                                               } />
+                                       </div>
+                                       {ITEMS.map(item =>
+                                               <div
+                                                       className={
+                                                               `cell ${state[dungeon][item] ? 'on' : 'off'} ${ITEM_CLASSES[item]}`
+                                                       }
+                                                       key={item}
+                                                       onClick={handleItemClick(dungeon, item)}
+                                               >
+                                                       <ZeldaIcon name={item} />
+                                               </div>
+                                       )}
+                               </div>
+                       )}
+               </div>
+       </>;
+};
diff --git a/resources/js/pages/Event.js b/resources/js/pages/Event.js
deleted file mode 100644 (file)
index fa5dc21..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-import axios from 'axios';
-import moment from 'moment';
-import React from 'react';
-import { Container } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-import { useParams } from 'react-router-dom';
-import toastr from 'toastr';
-
-import NotFound from './NotFound';
-import CanonicalLinks from '../components/common/CanonicalLinks';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import ErrorMessage from '../components/common/ErrorMessage';
-import Loading from '../components/common/Loading';
-import EpisodeList from '../components/episodes/List';
-import Detail from '../components/events/Detail';
-import Dialog from '../components/techniques/Dialog';
-import { hasConcluded } from '../helpers/Event';
-import {
-       mayEditContent,
-} from '../helpers/permissions';
-import { getTranslation } from '../helpers/Technique';
-import { useUser } from '../hooks/user';
-import i18n from '../i18n';
-
-export const Component = () => {
-       const params = useParams();
-       const { name } = params;
-       const { user } = useUser();
-       const { t } = useTranslation();
-
-       const [error, setError] = React.useState(null);
-       const [loading, setLoading] = React.useState(true);
-       const [event, setEvent] = React.useState(null);
-
-       const [editContent, setEditContent] = React.useState(null);
-       const [episodes, setEpisodes] = React.useState([]);
-       const [showContentDialog, setShowContentDialog] = React.useState(false);
-
-       const actions = React.useMemo(() => ({
-               editContent: mayEditContent(user) ? content => {
-                       setEditContent(content);
-                       setShowContentDialog(true);
-               } : null,
-       }), [user]);
-
-       const fetchEpisodes = React.useCallback((controller, event) => {
-               if (!event) {
-                       setEpisodes([]);
-                       return;
-               }
-               const params = {
-                       event: [event.id],
-               };
-               if (hasConcluded(event)) {
-                       params.limit = 25;
-                       params.reverse = '1';
-               } else {
-                       params.after = moment().subtract(3, 'hours').toISOString();
-                       params.before = moment().add(14, 'days').toISOString();
-               }
-               axios.get(`/api/episodes`, {
-                       signal: controller.signal,
-                       params,
-               }).then(response => {
-                       setEpisodes(response.data || []);
-               }).catch(e => {
-                       if (!axios.isCancel(e)) {
-                               console.error(e);
-                       }
-               });
-       }, []);
-
-       const saveContent = React.useCallback(async values => {
-               try {
-                       const response = await axios.put(`/api/content/${values.id}`, {
-                               parent_id: event.description_id,
-                               ...values,
-                       });
-                       toastr.success(t('content.saveSuccess'));
-                       setEvent(event => ({
-                               ...event,
-                               description: response.data,
-                       }));
-                       setShowContentDialog(false);
-               } catch (e) {
-                       toastr.error(t('content.saveError'));
-               }
-       }, [event && event.description_id]);
-
-       React.useEffect(() => {
-               const ctrl = new AbortController();
-               setLoading(true);
-               axios
-                       .get(`/api/events/${name}`, { signal: ctrl.signal })
-                       .then(response => {
-                               setError(null);
-                               setLoading(false);
-                               setEvent(response.data);
-                       })
-                       .catch(error => {
-                               setError(error);
-                               setLoading(false);
-                               setEvent(null);
-                       });
-               return () => {
-                       ctrl.abort();
-               };
-       }, [name]);
-
-       React.useEffect(() => {
-               const controller = new AbortController();
-               fetchEpisodes(controller, event);
-               const timer = setInterval(() => {
-                       fetchEpisodes(controller, event);
-               }, 1.5 * 60 * 1000);
-               return () => {
-                       controller.abort();
-                       clearInterval(timer);
-               };
-       }, [event, fetchEpisodes]);
-
-       if (loading) {
-               return <Loading />;
-       }
-
-       if (error) {
-               return <ErrorMessage error={error} />;
-       }
-
-       if (!event) {
-               return <NotFound />;
-       }
-
-       return <ErrorBoundary>
-               <Helmet>
-                       <title>
-                               {(event.description && getTranslation(event.description, 'title', i18n.language))
-                                       || event.title}
-                       </title>
-               </Helmet>
-               {event.description ? <Helmet>
-                       <meta
-                               name="description"
-                               content={getTranslation(event.description, 'short', i18n.language)}
-                       />
-               </Helmet> : null}
-               <CanonicalLinks base={`/events/${event.name}`} />
-               <Container>
-                       <Detail actions={actions} event={event} />
-                       {episodes.length ? <>
-                               <h2 className="mt-4">
-                                       {t(hasConcluded(event)
-                                               ? 'events.pastEpisodes'
-                                               : 'events.upcomingEpisodes'
-                                       )}
-                               </h2>
-                               <EpisodeList episodes={episodes} />
-                       </> : null}
-               </Container>
-               <Dialog
-                       content={editContent}
-                       language={i18n.language}
-                       onHide={() => { setShowContentDialog(false); }}
-                       onSubmit={saveContent}
-                       show={showContentDialog}
-               />
-       </ErrorBoundary>;
-};
diff --git a/resources/js/pages/Event.jsx b/resources/js/pages/Event.jsx
new file mode 100644 (file)
index 0000000..ef52e9f
--- /dev/null
@@ -0,0 +1,193 @@
+import axios from 'axios';
+import moment from 'moment';
+import React from 'react';
+import { Alert, Button, Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+import { useParams } from 'react-router-dom';
+import toastr from 'toastr';
+
+import NotFound from './NotFound';
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Icon from '../components/common/Icon';
+import Loading from '../components/common/Loading';
+import EpisodeList from '../components/episodes/List';
+import Detail from '../components/events/Detail';
+import Dialog from '../components/techniques/Dialog';
+import { hasConcluded } from '../helpers/Event';
+import {
+       mayEditContent,
+} from '../helpers/permissions';
+import { getTranslation } from '../helpers/Technique';
+import { useUser } from '../hooks/user';
+import i18n from '../i18n';
+
+export const Component = () => {
+       const params = useParams();
+       const { name } = params;
+       const { user } = useUser();
+       const { t } = useTranslation();
+
+       const [error, setError] = React.useState(null);
+       const [loading, setLoading] = React.useState(true);
+       const [event, setEvent] = React.useState(null);
+
+       const [editContent, setEditContent] = React.useState(null);
+       const [episodes, setEpisodes] = React.useState([]);
+       const [pastMode, setPastMode] = React.useState(false);
+       const [showContentDialog, setShowContentDialog] = React.useState(false);
+
+       const actions = React.useMemo(() => ({
+               editContent: mayEditContent(user) ? content => {
+                       setEditContent(content);
+                       setShowContentDialog(true);
+               } : null,
+       }), [user]);
+
+       const fetchEpisodes = React.useCallback((controller, event) => {
+               if (!event) {
+                       setEpisodes([]);
+                       return;
+               }
+               const params = {
+                       event: [event.id],
+               };
+               if (hasConcluded(event)) {
+                       params.limit = 25;
+                       params.reverse = '1';
+               } else if (pastMode) {
+                       params.before = moment().add(3, 'hours').toISOString();
+                       params.limit = 25;
+                       params.reverse = '1';
+               } else {
+                       params.after = moment().subtract(3, 'hours').toISOString();
+                       params.before = moment().add(14, 'days').toISOString();
+               }
+               axios.get(`/api/episodes`, {
+                       signal: controller.signal,
+                       params,
+               }).then(response => {
+                       setEpisodes(response.data || []);
+               }).catch(e => {
+                       if (!axios.isCancel(e)) {
+                               console.error(e);
+                       }
+               });
+       }, [pastMode]);
+
+       const saveContent = React.useCallback(async values => {
+               try {
+                       const response = await axios.put(`/api/content/${values.id}`, {
+                               parent_id: event.description_id,
+                               ...values,
+                       });
+                       toastr.success(t('content.saveSuccess'));
+                       setEvent(event => ({
+                               ...event,
+                               description: response.data,
+                       }));
+                       setShowContentDialog(false);
+               } catch (e) {
+                       toastr.error(t('content.saveError'));
+               }
+       }, [event && event.description_id]);
+
+       React.useEffect(() => {
+               const ctrl = new AbortController();
+               setLoading(true);
+               axios
+                       .get(`/api/events/${name}`, { signal: ctrl.signal })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setEvent(response.data);
+                       })
+                       .catch(error => {
+                               setError(error);
+                               setLoading(false);
+                               setEvent(null);
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [name]);
+
+       React.useEffect(() => {
+               const controller = new AbortController();
+               fetchEpisodes(controller, event);
+               const timer = setInterval(() => {
+                       fetchEpisodes(controller, event);
+               }, 1.5 * 60 * 1000);
+               return () => {
+                       controller.abort();
+                       clearInterval(timer);
+               };
+       }, [event, fetchEpisodes]);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       if (!event) {
+               return <NotFound />;
+       }
+
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>
+                               {(event.description && getTranslation(event.description, 'title', i18n.language))
+                                       || event.title}
+                       </title>
+               </Helmet>
+               {event.description ? <Helmet>
+                       <meta
+                               name="description"
+                               content={getTranslation(event.description, 'short', i18n.language)}
+                       />
+               </Helmet> : null}
+               <CanonicalLinks base={`/events/${event.name}`} />
+               <Container>
+                       <Detail actions={actions} event={event} />
+                       <div className="d-flex align-items-center justify-content-between">
+                               <h2 className="mt-4">
+                                       {t(pastMode || hasConcluded(event)
+                                               ? 'events.pastEpisodes'
+                                               : 'events.upcomingEpisodes'
+                                       )}
+                               </h2>
+                               <div className="button-bar">
+                                       {!hasConcluded(event) ?
+                                               <Button
+                                                       className="ms-3"
+                                                       onClick={() => setPastMode(!pastMode)}
+                                                       title={t(pastMode ? 'events.setFutureMode' : 'events.setPastMode')}
+                                                       variant="outline-secondary"
+                                               >
+                                                       <Icon.TIME_REVERSE title="" />
+                                               </Button>
+                                       : null}
+                               </div>
+                       </div>
+                       {episodes.length ?
+                               <EpisodeList episodes={episodes} />
+                       :
+                               <Alert variant="info">
+                                       {t(pastMode ? 'events.noPastEpisodes' : 'events.noUpcomingEpisodes')}
+                               </Alert>
+                       }
+               </Container>
+               <Dialog
+                       content={editContent}
+                       language={i18n.language}
+                       onHide={() => { setShowContentDialog(false); }}
+                       onSubmit={saveContent}
+                       show={showContentDialog}
+               />
+       </ErrorBoundary>;
+};
diff --git a/resources/js/pages/Events.js b/resources/js/pages/Events.js
deleted file mode 100644 (file)
index d7ecde2..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-import axios from 'axios';
-import React from 'react';
-import { Container } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-
-import CanonicalLinks from '../components/common/CanonicalLinks';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import ErrorMessage from '../components/common/ErrorMessage';
-import Loading from '../components/common/Loading';
-import List from '../components/events/List';
-
-export const Component = () => {
-       const { t } = useTranslation();
-
-       const [error, setError] = React.useState(null);
-       const [loading, setLoading] = React.useState(true);
-       const [events, setEvents] = React.useState([]);
-
-       const fetchEvents = React.useCallback(async (controller) => {
-               const params = {
-                       order: 'recency',
-                       with: ['description'],
-               };
-               try {
-                       const response = await axios.get(`/api/events`, {
-                               signal: controller.signal,
-                               params,
-                       });
-                       return response.data || [];
-               } catch (error) {
-                       if (!axios.isCancel(error)) {
-                               throw error;
-                       }
-                       return [];
-               }
-       }, []);
-
-       React.useEffect(() => {
-               const controller = new AbortController();
-               setLoading(true);
-               fetchEvents(controller)
-                       .then(events => {
-                               setError(null);
-                               setLoading(false);
-                               setEvents(events);
-                       })
-                       .catch(error => {
-                               setError(error);
-                               setLoading(false);
-                               setEvents([]);
-                       });
-               return () => {
-                       controller.abort();
-               };
-       }, [fetchEvents]);
-
-       const evergreen = React.useMemo(() =>
-               events.filter(event => !event.start)
-       , [events]);
-       const ongoing = React.useMemo(() =>
-               events.filter(event => event.start && !event.end)
-       , [events]);
-       const past = React.useMemo(() =>
-               events.filter(event => event.end)
-       , [events]);
-
-       if (loading) {
-               return <Loading />;
-       }
-
-       if (error) {
-               return <ErrorMessage error={error} />;
-       }
-
-       return <ErrorBoundary>
-               <Helmet>
-                       <title>
-                               {t('events.heading')}
-                       </title>
-               </Helmet>
-               <CanonicalLinks base={`/events`} />
-               <Container>
-                       <h1>{t('events.ongoing')}</h1>
-                       <List events={ongoing} />
-                       <h1>{t('events.evergreen')}</h1>
-                       <List events={evergreen} />
-                       <h1>{t('events.past')}</h1>
-                       <List events={past} />
-               </Container>
-       </ErrorBoundary>;
-};
diff --git a/resources/js/pages/Events.jsx b/resources/js/pages/Events.jsx
new file mode 100644 (file)
index 0000000..b65652e
--- /dev/null
@@ -0,0 +1,93 @@
+import axios from 'axios';
+import React from 'react';
+import { Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+import List from '../components/events/List';
+import { compareStart, hasConcluded, isEvergreen, isOngoing } from '../helpers/Event';
+
+export const Component = () => {
+       const { t } = useTranslation();
+
+       const [error, setError] = React.useState(null);
+       const [loading, setLoading] = React.useState(true);
+       const [events, setEvents] = React.useState([]);
+
+       const fetchEvents = React.useCallback(async (controller) => {
+               const params = {
+                       order: 'recency',
+                       with: ['description'],
+               };
+               try {
+                       const response = await axios.get(`/api/events`, {
+                               signal: controller.signal,
+                               params,
+                       });
+                       return response.data || [];
+               } catch (error) {
+                       if (!axios.isCancel(error)) {
+                               throw error;
+                       }
+                       return [];
+               }
+       }, []);
+
+       React.useEffect(() => {
+               const controller = new AbortController();
+               setLoading(true);
+               fetchEvents(controller)
+                       .then(events => {
+                               setError(null);
+                               setLoading(false);
+                               setEvents(events);
+                       })
+                       .catch(error => {
+                               setError(error);
+                               setLoading(false);
+                               setEvents([]);
+                       });
+               return () => {
+                       controller.abort();
+               };
+       }, [fetchEvents]);
+
+       const evergreen = React.useMemo(() =>
+               events.filter(isEvergreen)
+       , [events]);
+       const ongoing = React.useMemo(() =>
+               events.filter(isOngoing).sort((a, b) => compareStart(a, b) * -1)
+       , [events]);
+       const past = React.useMemo(() =>
+               events.filter(hasConcluded)
+       , [events]);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>
+                               {t('events.heading')}
+                       </title>
+               </Helmet>
+               <CanonicalLinks base={`/events`} />
+               <Container>
+                       <h1>{t('events.ongoing')}</h1>
+                       <List events={ongoing} />
+                       <h1>{t('events.evergreen')}</h1>
+                       <List events={evergreen} />
+                       <h1>{t('events.past')}</h1>
+                       <List events={past} />
+               </Container>
+       </ErrorBoundary>;
+};
diff --git a/resources/js/pages/Front.js b/resources/js/pages/Front.js
deleted file mode 100644 (file)
index 91ada1f..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import { Button, Col, Container, Image, Row } from 'react-bootstrap';
-import { useNavigate } from 'react-router-dom';
-
-import CanonicalLinks from '../components/common/CanonicalLinks';
-
-const Front = () => {
-       const navigate = useNavigate();
-
-       React.useEffect(() => {
-               const returnPath = localStorage.getItem('returnPath');
-               if (returnPath) {
-                       localStorage.removeItem('returnPath');
-                       navigate(returnPath);
-               }
-       }, []);
-
-       return <Container className="mt-5">
-               <CanonicalLinks base="/" />
-               <Row>
-                       <Col md={{ offset: 3, span: 6 }}>
-                               <Button
-                                       className="front-panel"
-                                       onClick={() => navigate('/tournaments/6')}
-                                       variant="outline-secondary"
-                               >
-                                       <Image alt="" className="image" src="/media/alttp/front.png" />
-                                       <div className="title">
-                                               ALttPR Weekly
-                                       </div>
-                               </Button>
-                       </Col>
-               </Row>
-       </Container>;
-};
-
-export default Front;
diff --git a/resources/js/pages/Front.jsx b/resources/js/pages/Front.jsx
new file mode 100644 (file)
index 0000000..f0485ed
--- /dev/null
@@ -0,0 +1,83 @@
+import React from 'react';
+import { Button, Col, Container, Image, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import { Link, useNavigate } from 'react-router-dom';
+
+import CanonicalLinks from '../components/common/CanonicalLinks';
+
+const Front = () => {
+       const navigate = useNavigate();
+       const { t } = useTranslation();
+
+       React.useEffect(() => {
+               const returnPath = localStorage.getItem('returnPath');
+               if (returnPath) {
+                       localStorage.removeItem('returnPath');
+                       navigate(returnPath);
+               }
+       }, []);
+
+       return <Container className="front-page">
+               <CanonicalLinks base="/" />
+               <h1>{t('front.title')}</h1>
+               <h2>{t('front.tournaments')}</h2>
+               <Row>
+                       <Col sm={6}>
+                               <Link className="front-panel" to="/tournaments/6">
+                                       <Image alt="" className="image" src="/media/alttp/front.png" />
+                                       <div className="title">
+                                               {t('front.sdw')}
+                                       </div>
+                               </Link>
+                       </Col>
+                       <Col sm={6}>
+                               <Link className="front-panel" to="/tournaments/6">
+                                       <Image alt="" className="image" src="/media/alttp/front.png" />
+                                       <div className="title">
+                                               {t('front.circus')}
+                                       </div>
+                               </Link>
+                       </Col>
+               </Row>
+               <h2>{t('front.events')}</h2>
+               <Row>
+                       <Col sm={6}>
+                               <Link className="front-panel" to="/events">
+                                       <Image alt="" className="image" src="/media/alttp/front.png" />
+                                       <div className="title">
+                                               {t('front.eventlist')}
+                                       </div>
+                               </Link>
+                       </Col>
+                       <Col sm={6}>
+                               <Link className="front-panel" to="/schedule">
+                                       <Image alt="" className="image" src="/media/alttp/front.png" />
+                                       <div className="title">
+                                               {t('front.schedule')}
+                                       </div>
+                               </Link>
+                       </Col>
+               </Row>
+               <h2>{t('front.resources')}</h2>
+               <Row>
+                       <Col sm={6}>
+                               <Link className="front-panel" to="/tech">
+                                       <Image alt="" className="image" src="/media/alttp/front.png" />
+                                       <div className="title">
+                                               {t('front.tech')}
+                                       </div>
+                               </Link>
+                       </Col>
+                       <Col sm={6}>
+                               <Link className="front-panel" to="/map/lw">
+                                       <Image alt="" className="image" src="/media/alttp/front.png" />
+                                       <div className="title">
+                                               {t('front.map')}
+                                       </div>
+                               </Link>
+                       </Col>
+               </Row>
+       </Container>;
+};
+
+export default Front;
diff --git a/resources/js/pages/GuessingGameControls.js b/resources/js/pages/GuessingGameControls.js
deleted file mode 100644 (file)
index 192e399..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-import axios from 'axios';
-import React from 'react';
-import { Alert, Col, Container, Form, Navbar, Row } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-import { useParams } from 'react-router-dom';
-import toastr from 'toastr';
-
-import User from '../app/User';
-import ChannelSelect from '../components/common/ChannelSelect';
-import GuessingGameControls from '../components/twitch-bot/GuessingGameControls';
-import GuessingGuess from '../components/twitch-bot/GuessingGuess';
-import GuessingWinner from '../components/twitch-bot/GuessingWinner';
-import { patchGuess, patchWinner } from '../helpers/Channel';
-
-export const Component = () => {
-       const [channel, setChannel] = React.useState(null);
-       const [guesses, setGuesses] = React.useState([]);
-       const [winners, setWinners] = React.useState([]);
-
-       const { channelId } = useParams();
-       const { t } = useTranslation();
-
-       React.useEffect(() => {
-               if (!channelId) return;
-               const fetchChannel = async () => {
-                       const response = await axios.get(`/api/channels`, {
-                               params: {
-                                       id: [channelId],
-                                       manageable: 1,
-                               },
-                       });
-                       if (response.data.length) {
-                               setChannel(response.data[0]);
-                       }
-               };
-               fetchChannel();
-       }, [channelId]);
-
-       React.useEffect(() => {
-               if (!channel) {
-                       setGuesses([]);
-                       setWinners([]);
-                       return;
-               }
-               if (channel.guessing_type) {
-                       axios.get(`/api/channels/${channel.id}/guessing-game/${channel.guessing_type}`)
-                               .then(res => {
-                                       res.data.guesses.forEach(g => {
-                                               setGuesses(gs => patchGuess(gs, g));
-                                       });
-                                       res.data.winners.forEach(w => {
-                                               setWinners(ws => patchGuess(ws, w));
-                                       });
-                               });
-               }
-               window.Echo.private(`Channel.${channel.id}`)
-                       .listen('.GuessingGuessCreated', (e) => {
-                               setGuesses(gs => patchGuess(gs, e.model));
-                       })
-                       .listen('.GuessingWinnerCreated', (e) => {
-                               setWinners(ws => patchWinner(ws, e.model));
-                       })
-                       .listen('.ChannelUpdated', (e) => {
-                               setChannel(c => ({ ...c, ...e.model }));
-                       });
-               return () => {
-                       window.Echo.leave(`Channel.${channel.id}`);
-               };
-       }, [channel && channel.id]);
-
-       React.useEffect(() => {
-               const cutoff = channel && channel.guessing_start;
-               if (cutoff) {
-                       setGuesses(gs => gs.filter(g => g.created_at >= cutoff));
-                       setWinners(ws => ws.filter(w => w.created_at >= cutoff));
-               }
-       }, [channel && channel.guessing_start]);
-
-       const onCancel = React.useCallback(async () => {
-               try {
-                       const rsp = await axios.post(
-                               `/api/channels/${channel.id}/guessing-game/gtbk`,
-                               { action: 'cancel' },
-                       );
-                       setChannel(rsp.data);
-               } catch (e) {
-                       toastr.error(t('twitchBot.controlError'));
-               }
-       }, [channel]);
-
-       const onSolve = React.useCallback(async (solution) => {
-               try {
-                       const rsp = await axios.post(
-                               `/api/channels/${channel.id}/guessing-game/gtbk`,
-                               { action: 'solve', solution },
-                       );
-                       setChannel(rsp.data);
-               } catch (e) {
-                       toastr.error(t('twitchBot.controlError'));
-               }
-       }, [channel]);
-
-       const onStart = React.useCallback(async () => {
-               try {
-                       const rsp = await axios.post(
-                               `/api/channels/${channel.id}/guessing-game/gtbk`,
-                               { action: 'start' },
-                       );
-                       setChannel(rsp.data);
-               } catch (e) {
-                       toastr.error(t('twitchBot.controlError'));
-               }
-       }, [channel]);
-
-       const onStop = React.useCallback(async () => {
-               try {
-                       const rsp = await axios.post(
-                               `/api/channels/${channel.id}/guessing-game/gtbk`,
-                               { action: 'stop' },
-                       );
-                       setChannel(rsp.data);
-               } catch (e) {
-                       toastr.error(t('twitchBot.controlError'));
-               }
-       }, [channel]);
-
-       return <>
-               <Helmet>
-                       <title>Guessing Game Controls</title>
-               </Helmet>
-               <Navbar id="header" bg="dark" variant="dark">
-                       <Container fluid>
-                               <Form.Control
-                                       as={ChannelSelect}
-                                       autoSelect
-                                       joinable
-                                       manageable
-                                       onChange={({ channel }) => { setChannel(channel); }}
-                                       readOnly={!!(channelId && channel)}
-                                       value={channel ? channel.id : channelId}
-                               />
-                               <User />
-                       </Container>
-               </Navbar>
-               <Container fluid>
-               {channel ? <Row>
-                       <Col md={12} lg={6}>
-                               <GuessingGameControls
-                                       channel={channel}
-                                       onCancel={onCancel}
-                                       onSolve={onSolve}
-                                       onStart={onStart}
-                                       onStop={onStop}
-                               />
-                       </Col>
-                       <Col md={6} lg={3}>
-                               <h3 className="mt-3">{t('twitchBot.guessingGame.winners')}</h3>
-                               {winners.map(winner =>
-                                       <GuessingWinner key={winner.id} winner={winner} />
-                               )}
-                       </Col>
-                       <Col md={6} lg={3}>
-                               <h3 className="mt-3">{t('twitchBot.guessingGame.guesses')}</h3>
-                               {guesses.map(guess =>
-                                       <GuessingGuess guess={guess} key={guess.id} />
-                               )}
-                       </Col>
-               </Row> :
-                       <Alert variant="info">
-                               {t('twitchBot.selectChannel')}
-                       </Alert>
-               }
-               </Container>
-       </>;
-};
diff --git a/resources/js/pages/GuessingGameControls.jsx b/resources/js/pages/GuessingGameControls.jsx
new file mode 100644 (file)
index 0000000..192e399
--- /dev/null
@@ -0,0 +1,176 @@
+import axios from 'axios';
+import React from 'react';
+import { Alert, Col, Container, Form, Navbar, Row } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+import { useParams } from 'react-router-dom';
+import toastr from 'toastr';
+
+import User from '../app/User';
+import ChannelSelect from '../components/common/ChannelSelect';
+import GuessingGameControls from '../components/twitch-bot/GuessingGameControls';
+import GuessingGuess from '../components/twitch-bot/GuessingGuess';
+import GuessingWinner from '../components/twitch-bot/GuessingWinner';
+import { patchGuess, patchWinner } from '../helpers/Channel';
+
+export const Component = () => {
+       const [channel, setChannel] = React.useState(null);
+       const [guesses, setGuesses] = React.useState([]);
+       const [winners, setWinners] = React.useState([]);
+
+       const { channelId } = useParams();
+       const { t } = useTranslation();
+
+       React.useEffect(() => {
+               if (!channelId) return;
+               const fetchChannel = async () => {
+                       const response = await axios.get(`/api/channels`, {
+                               params: {
+                                       id: [channelId],
+                                       manageable: 1,
+                               },
+                       });
+                       if (response.data.length) {
+                               setChannel(response.data[0]);
+                       }
+               };
+               fetchChannel();
+       }, [channelId]);
+
+       React.useEffect(() => {
+               if (!channel) {
+                       setGuesses([]);
+                       setWinners([]);
+                       return;
+               }
+               if (channel.guessing_type) {
+                       axios.get(`/api/channels/${channel.id}/guessing-game/${channel.guessing_type}`)
+                               .then(res => {
+                                       res.data.guesses.forEach(g => {
+                                               setGuesses(gs => patchGuess(gs, g));
+                                       });
+                                       res.data.winners.forEach(w => {
+                                               setWinners(ws => patchGuess(ws, w));
+                                       });
+                               });
+               }
+               window.Echo.private(`Channel.${channel.id}`)
+                       .listen('.GuessingGuessCreated', (e) => {
+                               setGuesses(gs => patchGuess(gs, e.model));
+                       })
+                       .listen('.GuessingWinnerCreated', (e) => {
+                               setWinners(ws => patchWinner(ws, e.model));
+                       })
+                       .listen('.ChannelUpdated', (e) => {
+                               setChannel(c => ({ ...c, ...e.model }));
+                       });
+               return () => {
+                       window.Echo.leave(`Channel.${channel.id}`);
+               };
+       }, [channel && channel.id]);
+
+       React.useEffect(() => {
+               const cutoff = channel && channel.guessing_start;
+               if (cutoff) {
+                       setGuesses(gs => gs.filter(g => g.created_at >= cutoff));
+                       setWinners(ws => ws.filter(w => w.created_at >= cutoff));
+               }
+       }, [channel && channel.guessing_start]);
+
+       const onCancel = React.useCallback(async () => {
+               try {
+                       const rsp = await axios.post(
+                               `/api/channels/${channel.id}/guessing-game/gtbk`,
+                               { action: 'cancel' },
+                       );
+                       setChannel(rsp.data);
+               } catch (e) {
+                       toastr.error(t('twitchBot.controlError'));
+               }
+       }, [channel]);
+
+       const onSolve = React.useCallback(async (solution) => {
+               try {
+                       const rsp = await axios.post(
+                               `/api/channels/${channel.id}/guessing-game/gtbk`,
+                               { action: 'solve', solution },
+                       );
+                       setChannel(rsp.data);
+               } catch (e) {
+                       toastr.error(t('twitchBot.controlError'));
+               }
+       }, [channel]);
+
+       const onStart = React.useCallback(async () => {
+               try {
+                       const rsp = await axios.post(
+                               `/api/channels/${channel.id}/guessing-game/gtbk`,
+                               { action: 'start' },
+                       );
+                       setChannel(rsp.data);
+               } catch (e) {
+                       toastr.error(t('twitchBot.controlError'));
+               }
+       }, [channel]);
+
+       const onStop = React.useCallback(async () => {
+               try {
+                       const rsp = await axios.post(
+                               `/api/channels/${channel.id}/guessing-game/gtbk`,
+                               { action: 'stop' },
+                       );
+                       setChannel(rsp.data);
+               } catch (e) {
+                       toastr.error(t('twitchBot.controlError'));
+               }
+       }, [channel]);
+
+       return <>
+               <Helmet>
+                       <title>Guessing Game Controls</title>
+               </Helmet>
+               <Navbar id="header" bg="dark" variant="dark">
+                       <Container fluid>
+                               <Form.Control
+                                       as={ChannelSelect}
+                                       autoSelect
+                                       joinable
+                                       manageable
+                                       onChange={({ channel }) => { setChannel(channel); }}
+                                       readOnly={!!(channelId && channel)}
+                                       value={channel ? channel.id : channelId}
+                               />
+                               <User />
+                       </Container>
+               </Navbar>
+               <Container fluid>
+               {channel ? <Row>
+                       <Col md={12} lg={6}>
+                               <GuessingGameControls
+                                       channel={channel}
+                                       onCancel={onCancel}
+                                       onSolve={onSolve}
+                                       onStart={onStart}
+                                       onStop={onStop}
+                               />
+                       </Col>
+                       <Col md={6} lg={3}>
+                               <h3 className="mt-3">{t('twitchBot.guessingGame.winners')}</h3>
+                               {winners.map(winner =>
+                                       <GuessingWinner key={winner.id} winner={winner} />
+                               )}
+                       </Col>
+                       <Col md={6} lg={3}>
+                               <h3 className="mt-3">{t('twitchBot.guessingGame.guesses')}</h3>
+                               {guesses.map(guess =>
+                                       <GuessingGuess guess={guess} key={guess.id} />
+                               )}
+                       </Col>
+               </Row> :
+                       <Alert variant="info">
+                               {t('twitchBot.selectChannel')}
+                       </Alert>
+               }
+               </Container>
+       </>;
+};
diff --git a/resources/js/pages/GuessingGameMonitor.js b/resources/js/pages/GuessingGameMonitor.js
deleted file mode 100644 (file)
index bf2922b..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-import axios from 'axios';
-import moment from 'moment';
-import React from 'react';
-import { Container } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useParams } from 'react-router-dom';
-
-import {
-       hasActiveGuessing,
-       isAcceptingGuesses,
-       patchGuess,
-       patchWinner,
-} from '../helpers/Channel';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import Icon from '../components/common/Icon';
-import Slider from '../components/common/Slider';
-
-export const Component = () => {
-       const [channel, setChannel] = React.useState({});
-       const [guesses, setGuesses] = React.useState([]);
-       const [winnerExpiry, setWinnerExpiry] = React.useState(moment().subtract(15, 'second'));
-       const [winners, setWinners] = React.useState([]);
-
-       const params = useParams();
-       const { key } = params;
-
-       React.useEffect(() => {
-               if (!key) return;
-               axios.get(`/api/guessing-game-monitor/${key}`)
-                       .then(res => {
-                               setChannel(res.data.channel);
-                               res.data.guesses.forEach(g => {
-                                       setGuesses(gs => patchGuess(gs, g));
-                               });
-                               res.data.winners.forEach(w => {
-                                       setWinners(ws => patchGuess(ws, w));
-                               });
-                       });
-               window.Echo.channel(`ChannelKey.${key}`)
-                       .listen('.GuessingGuessCreated', (e) => {
-                               setGuesses(gs => patchGuess(gs, e.model));
-                       })
-                       .listen('.GuessingWinnerCreated', (e) => {
-                               setWinners(ws => patchWinner(ws, e.model));
-                       })
-                       .listen('.ChannelUpdated', (e) => {
-                               setChannel(c => ({ ...c, ...e.model }));
-                       });
-               return () => {
-                       window.Echo.leave(`ChannelKey.${key}`);
-               };
-       }, [key]);
-
-       React.useEffect(() => {
-               if (isAcceptingGuesses(channel)) {
-                       setGuesses(gs => gs.filter(g => g.created_at >= channel.guessing_start));
-                       setWinners([]);
-               }
-       }, [channel]);
-
-       React.useEffect(() => {
-               const interval = setInterval(() => {
-                       setWinnerExpiry(moment().subtract(15, 'second'));
-               }, 1000);
-               return () => {
-                       clearInterval(interval);
-               };
-       }, []);
-
-       const guessingStats = React.useMemo(() => {
-               const stats = {
-                       counts: [],
-                       lastWin: null,
-                       max: 0,
-                       wins: [],
-                       winners: [],
-               };
-               for (let i = 0; i < 22; ++i) {
-                       stats.counts.push(0);
-                       stats.wins.push(false);
-               }
-               const seen = [];
-               guesses.forEach(guess => {
-                       if (seen[guess.uid]) {
-                               --stats.counts[parseInt(seen[guess.uid].guess, 10) - 1];
-                       }
-                       ++stats.counts[parseInt(guess.guess, 10) - 1];
-                       seen[guess.uid] = guess;
-               });
-               winners.forEach(winner => {
-                       if (winner.score) {
-                               stats.wins[parseInt(winner.guess, 10) - 1] = true;
-                               stats.winners.push(winner.uname);
-                       }
-                       if (!stats.lastWin || stats.lastWin < winner.created_at) {
-                               stats.lastWin = winner.created_at;
-                       }
-               });
-               for (let i = 0; i < 22; ++i) {
-                       if (stats.counts[i] > stats.max) {
-                               stats.max = stats.counts[i];
-                       }
-               }
-               return stats;
-       }, [guesses, winners]);
-
-       const getNumberHeight = React.useCallback((number) => {
-               if (!guessingStats || !guessingStats.max) return 3;
-               if (!number) return 3;
-               return Math.max(0.05, number / guessingStats.max) * 100;
-       }, [guessingStats]);
-
-       const getStatClass = React.useCallback((index) => {
-               const names = ['guessing-stat'];
-               if (guessingStats.wins[index]) {
-                       names.push('has-won');
-               }
-               return names.join(' ');
-       }, [guessingStats]);
-
-       const showOpen = React.useMemo(() => {
-               return isAcceptingGuesses(channel);
-       }, [channel]);
-
-       const showClosed = React.useMemo(() => {
-               return hasActiveGuessing(channel) && !isAcceptingGuesses(channel);
-       }, [channel]);
-
-       const showWinners = React.useMemo(() => {
-               return !hasActiveGuessing(channel) && (
-                       guessingStats?.lastWin &&
-                       moment(guessingStats.lastWin).isAfter(winnerExpiry));
-       }, [channel, guessingStats, winnerExpiry]);
-
-       return <ErrorBoundary>
-               <Helmet>
-                       <title>Guessing Game</title>
-               </Helmet>
-               <Container className="guessing-game-monitor" fluid>
-               {showOpen || showClosed || showWinners ?
-                       <div className="message-box">
-                               {showOpen ?
-                                       <div className="message-title accepting-guesses">
-                                               <Icon.WARNING className="message-icon" />
-                                               <div className="message-text">
-                                                       <Slider duration={3500}>
-                                                               <Slider.Slide>GT Big Key Guessing Game</Slider.Slide>
-                                                               <Slider.Slide>Zahlen von 1 bis 22 in den Chat!</Slider.Slide>
-                                                       </Slider>
-                                               </div>
-                                               <Icon.WARNING className="message-icon" />
-                                       </div>
-                               : null}
-                               {showClosed ?
-                                       <div className="message-title guessing-closed">
-                                               <div className="message-text">
-                                                       Anmeldung geschlossen
-                                               </div>
-                                       </div>
-                               : null}
-                               {showWinners ?
-                                       <div className="message-title guessing-winners">
-                                               <div className="message-text">
-                                                       {guessingStats.winners.length ?
-                                                               <Slider duration={2500}>
-                                                                       <Slider.Slide>Herzlichen Glückwunsch!</Slider.Slide>
-                                                                       {guessingStats.winners.map(winner =>
-                                                                               <Slider.Slide key={winner}>{winner}</Slider.Slide>
-                                                                       )}
-                                                               </Slider>
-                                                       :
-                                                               'Leider keiner richtig'
-                                                       }
-                                               </div>
-                                       </div>
-                               : null}
-                               <div className="guessing-stats">
-                                       {guessingStats.counts.map((number, index) =>
-                                               <div className={getStatClass(index)} key={index}>
-                                                       <div className="guessing-box">
-                                                               <div
-                                                                       className="guessing-box-bar"
-                                                                       style={{ height: `${getNumberHeight(number)}%` }}
-                                                               />
-                                                       </div>
-                                                       <div className="guessing-number">{index + 1}</div>
-                                               </div>
-                                       )}
-                               </div>
-                       </div>
-               : null}
-               </Container>
-       </ErrorBoundary>;
-};
diff --git a/resources/js/pages/GuessingGameMonitor.jsx b/resources/js/pages/GuessingGameMonitor.jsx
new file mode 100644 (file)
index 0000000..bf2922b
--- /dev/null
@@ -0,0 +1,194 @@
+import axios from 'axios';
+import moment from 'moment';
+import React from 'react';
+import { Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useParams } from 'react-router-dom';
+
+import {
+       hasActiveGuessing,
+       isAcceptingGuesses,
+       patchGuess,
+       patchWinner,
+} from '../helpers/Channel';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import Icon from '../components/common/Icon';
+import Slider from '../components/common/Slider';
+
+export const Component = () => {
+       const [channel, setChannel] = React.useState({});
+       const [guesses, setGuesses] = React.useState([]);
+       const [winnerExpiry, setWinnerExpiry] = React.useState(moment().subtract(15, 'second'));
+       const [winners, setWinners] = React.useState([]);
+
+       const params = useParams();
+       const { key } = params;
+
+       React.useEffect(() => {
+               if (!key) return;
+               axios.get(`/api/guessing-game-monitor/${key}`)
+                       .then(res => {
+                               setChannel(res.data.channel);
+                               res.data.guesses.forEach(g => {
+                                       setGuesses(gs => patchGuess(gs, g));
+                               });
+                               res.data.winners.forEach(w => {
+                                       setWinners(ws => patchGuess(ws, w));
+                               });
+                       });
+               window.Echo.channel(`ChannelKey.${key}`)
+                       .listen('.GuessingGuessCreated', (e) => {
+                               setGuesses(gs => patchGuess(gs, e.model));
+                       })
+                       .listen('.GuessingWinnerCreated', (e) => {
+                               setWinners(ws => patchWinner(ws, e.model));
+                       })
+                       .listen('.ChannelUpdated', (e) => {
+                               setChannel(c => ({ ...c, ...e.model }));
+                       });
+               return () => {
+                       window.Echo.leave(`ChannelKey.${key}`);
+               };
+       }, [key]);
+
+       React.useEffect(() => {
+               if (isAcceptingGuesses(channel)) {
+                       setGuesses(gs => gs.filter(g => g.created_at >= channel.guessing_start));
+                       setWinners([]);
+               }
+       }, [channel]);
+
+       React.useEffect(() => {
+               const interval = setInterval(() => {
+                       setWinnerExpiry(moment().subtract(15, 'second'));
+               }, 1000);
+               return () => {
+                       clearInterval(interval);
+               };
+       }, []);
+
+       const guessingStats = React.useMemo(() => {
+               const stats = {
+                       counts: [],
+                       lastWin: null,
+                       max: 0,
+                       wins: [],
+                       winners: [],
+               };
+               for (let i = 0; i < 22; ++i) {
+                       stats.counts.push(0);
+                       stats.wins.push(false);
+               }
+               const seen = [];
+               guesses.forEach(guess => {
+                       if (seen[guess.uid]) {
+                               --stats.counts[parseInt(seen[guess.uid].guess, 10) - 1];
+                       }
+                       ++stats.counts[parseInt(guess.guess, 10) - 1];
+                       seen[guess.uid] = guess;
+               });
+               winners.forEach(winner => {
+                       if (winner.score) {
+                               stats.wins[parseInt(winner.guess, 10) - 1] = true;
+                               stats.winners.push(winner.uname);
+                       }
+                       if (!stats.lastWin || stats.lastWin < winner.created_at) {
+                               stats.lastWin = winner.created_at;
+                       }
+               });
+               for (let i = 0; i < 22; ++i) {
+                       if (stats.counts[i] > stats.max) {
+                               stats.max = stats.counts[i];
+                       }
+               }
+               return stats;
+       }, [guesses, winners]);
+
+       const getNumberHeight = React.useCallback((number) => {
+               if (!guessingStats || !guessingStats.max) return 3;
+               if (!number) return 3;
+               return Math.max(0.05, number / guessingStats.max) * 100;
+       }, [guessingStats]);
+
+       const getStatClass = React.useCallback((index) => {
+               const names = ['guessing-stat'];
+               if (guessingStats.wins[index]) {
+                       names.push('has-won');
+               }
+               return names.join(' ');
+       }, [guessingStats]);
+
+       const showOpen = React.useMemo(() => {
+               return isAcceptingGuesses(channel);
+       }, [channel]);
+
+       const showClosed = React.useMemo(() => {
+               return hasActiveGuessing(channel) && !isAcceptingGuesses(channel);
+       }, [channel]);
+
+       const showWinners = React.useMemo(() => {
+               return !hasActiveGuessing(channel) && (
+                       guessingStats?.lastWin &&
+                       moment(guessingStats.lastWin).isAfter(winnerExpiry));
+       }, [channel, guessingStats, winnerExpiry]);
+
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>Guessing Game</title>
+               </Helmet>
+               <Container className="guessing-game-monitor" fluid>
+               {showOpen || showClosed || showWinners ?
+                       <div className="message-box">
+                               {showOpen ?
+                                       <div className="message-title accepting-guesses">
+                                               <Icon.WARNING className="message-icon" />
+                                               <div className="message-text">
+                                                       <Slider duration={3500}>
+                                                               <Slider.Slide>GT Big Key Guessing Game</Slider.Slide>
+                                                               <Slider.Slide>Zahlen von 1 bis 22 in den Chat!</Slider.Slide>
+                                                       </Slider>
+                                               </div>
+                                               <Icon.WARNING className="message-icon" />
+                                       </div>
+                               : null}
+                               {showClosed ?
+                                       <div className="message-title guessing-closed">
+                                               <div className="message-text">
+                                                       Anmeldung geschlossen
+                                               </div>
+                                       </div>
+                               : null}
+                               {showWinners ?
+                                       <div className="message-title guessing-winners">
+                                               <div className="message-text">
+                                                       {guessingStats.winners.length ?
+                                                               <Slider duration={2500}>
+                                                                       <Slider.Slide>Herzlichen Glückwunsch!</Slider.Slide>
+                                                                       {guessingStats.winners.map(winner =>
+                                                                               <Slider.Slide key={winner}>{winner}</Slider.Slide>
+                                                                       )}
+                                                               </Slider>
+                                                       :
+                                                               'Leider keiner richtig'
+                                                       }
+                                               </div>
+                                       </div>
+                               : null}
+                               <div className="guessing-stats">
+                                       {guessingStats.counts.map((number, index) =>
+                                               <div className={getStatClass(index)} key={index}>
+                                                       <div className="guessing-box">
+                                                               <div
+                                                                       className="guessing-box-bar"
+                                                                       style={{ height: `${getNumberHeight(number)}%` }}
+                                                               />
+                                                       </div>
+                                                       <div className="guessing-number">{index + 1}</div>
+                                               </div>
+                                       )}
+                               </div>
+                       </div>
+               : null}
+               </Container>
+       </ErrorBoundary>;
+};
diff --git a/resources/js/pages/HorstieLog.jsx b/resources/js/pages/HorstieLog.jsx
new file mode 100644 (file)
index 0000000..25661e0
--- /dev/null
@@ -0,0 +1,121 @@
+import axios from 'axios';
+import React from 'react';
+import { Col, Container, Row } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+
+import ChannelList from '../components/channel/List';
+import List from '../components/chat-bot-logs/List';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+import { compareHorstieLog } from '../helpers/Channel';
+
+export const Component = () => {
+       const [channels, setChannels] = React.useState([]);
+       const [error, setError] = React.useState(null);
+       const [loading, setLoading] = React.useState(true);
+       const [log, setLog] = React.useState([]);
+
+       const { t } = useTranslation();
+
+       React.useEffect(() => {
+               const ctrl = new AbortController();
+               if (!log.length) {
+                       setLoading(true);
+               }
+               axios
+                       .get(`/api/chatbotlogs/`, {
+                               signal: ctrl.signal,
+                       })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setLog(response.data);
+                       })
+                       .catch(error => {
+                               if (!axios.isCancel(error)) {
+                                       setError(error);
+                                       setLoading(false);
+                                       setLog([]);
+                               }
+                       });
+                       window.Echo.channel(`ChatBotLog`)
+                               .listen('.ChatBotLogCreated', (e) => {
+                                       setLog(l => [e.model, ...l]);
+                               });
+               return () => {
+                       ctrl.abort();
+                       window.Echo.leave(`ChatBotLog`);
+               };
+       }, []);
+
+       React.useEffect(() => {
+               const ctrl = new AbortController();
+               axios
+                       .get(`/api/channels`, {
+                               signal: ctrl.signal,
+                               params: {
+                                       chatting: 1,
+                               },
+                       })
+                       .then(response => {
+                               setChannels(response.data.sort(compareHorstieLog));
+                       })
+                       .catch(error => {
+                               if (!axios.isCancel(error)) {
+                                       setChannels([]);
+                               }
+                       });
+                       window.Echo.channel(`Channel`)
+                               .listen('.ChannelCreated', (e) => {
+                                       if (e.model.chat) {
+                                               setChannels(cs => [e.model, ...cs].sort(compareHorstieLog));
+                                       }
+                               })
+                               .listen('.ChannelUpdated', (e) => {
+                                       if (e.model.chat) {
+                                               setChannels(cs => {
+                                                       if (cs.find(c => c.id === e.model.id)) {
+                                                               return cs
+                                                                       .map(c => c.id === e.model.id ? e.model : c)
+                                                                       .sort(compareHorstieLog);
+                                                       } else {
+                                                               return [e.model, ...cs].sort(compareHorstieLog);
+                                                       }
+                                               });
+                                       } else {
+                                               setChannels(cs => cs.filter(c => c.id !== e.model.id));
+                                       }
+                               });
+               return () => {
+                       ctrl.abort();
+               };
+       }, []);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       return <Container>
+               <h1>Horstie Log</h1>
+               <Helmet>
+                       <title>Horstie Log</title>
+               </Helmet>
+               <ErrorBoundary>
+                       <Row>
+                               <Col md={9}>
+                                       <List log={log} />
+                               </Col>
+                               <Col className="horstielog-channels">
+                                       <h2 className="fs-4">{t('twitchBot.chatChannels')}</h2>
+                                       <ChannelList channels={channels} />
+                               </Col>
+                       </Row>
+               </ErrorBoundary>
+       </Container>;
+};
diff --git a/resources/js/pages/Map.js b/resources/js/pages/Map.js
deleted file mode 100644 (file)
index cd3d96d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import { Container } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-import { useParams } from 'react-router';
-
-import CanonicalLinks from '../components/common/CanonicalLinks';
-import Buttons from '../components/map/Buttons';
-import List from '../components/map/List';
-import OpenSeadragon from '../components/map/OpenSeadragon';
-import Pins from '../components/map/Pins';
-import UWSuperTiles from '../components/map/UWSuperTiles';
-
-export const Component = () => {
-       const [uwOverlay, setUWOverlay] = React.useState(false);
-
-       const { activeMap } = useParams();
-       const container = React.useRef();
-       const { t } = useTranslation();
-
-       return <Container fluid>
-               <Helmet>
-                       <title>{t('map.heading')} - {t(`map.${activeMap}Long`)}</title>
-                       <meta name="description" content={t('map.description')} />
-               </Helmet>
-               <CanonicalLinks base={`/map/${activeMap}`} />
-               <OpenSeadragon ref={container}>
-                       <div className="d-flex align-items-start justify-content-between">
-                               <h1>{t('map.heading')} - {t(`map.${activeMap}Long`)}</h1>
-                               <Buttons setUWOverlay={setUWOverlay} uwOverlay={uwOverlay} />
-                       </div>
-                       <div ref={container} style={{ height: '80vh' }} />
-                       <Pins />
-                       <UWSuperTiles show={uwOverlay} />
-                       <List />
-               </OpenSeadragon>
-       </Container>;
-};
diff --git a/resources/js/pages/Map.jsx b/resources/js/pages/Map.jsx
new file mode 100644 (file)
index 0000000..1ffd45a
--- /dev/null
@@ -0,0 +1,38 @@
+import React from 'react';
+import { Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+import { useParams } from 'react-router';
+
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import Buttons from '../components/map/Buttons';
+import List from '../components/map/List';
+import OpenSeadragon from '../components/map/OpenSeadragon';
+import Pins from '../components/map/Pins';
+import UWSuperTiles from '../components/map/UWSuperTiles';
+
+export const Component = () => {
+       const [uwOverlay, setUWOverlay] = React.useState(false);
+
+       const { activeMap } = useParams();
+       const container = React.useRef();
+       const { t } = useTranslation();
+
+       return <Container fluid>
+               <Helmet>
+                       <title>{t('map.heading')} - {t(`map.${activeMap}Long`)}</title>
+                       <meta name="description" content={t('map.description')} />
+               </Helmet>
+               <CanonicalLinks base={`/map/${activeMap}`} />
+               <OpenSeadragon containerRef={container}>
+                       <div className="d-flex align-items-start justify-content-between">
+                               <h1>{t('map.heading')} - {t(`map.${activeMap}Long`)}</h1>
+                               <Buttons setUWOverlay={setUWOverlay} uwOverlay={uwOverlay} />
+                       </div>
+                       <div ref={container} style={{ height: '80vh' }} />
+                       <Pins />
+                       <UWSuperTiles show={uwOverlay} />
+                       <List />
+               </OpenSeadragon>
+       </Container>;
+};
diff --git a/resources/js/pages/NotFound.js b/resources/js/pages/NotFound.js
deleted file mode 100644 (file)
index 19ccc72..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import { Helmet } from 'react-helmet';
-
-const NotFound = () =>
-       <div>
-               <Helmet>
-                       <title>Not Found</title>
-               </Helmet>
-               <h1>Not Found</h1>
-               <p>Sorry</p>
-       </div>;
-
-export default NotFound;
diff --git a/resources/js/pages/NotFound.jsx b/resources/js/pages/NotFound.jsx
new file mode 100644 (file)
index 0000000..19ccc72
--- /dev/null
@@ -0,0 +1,13 @@
+import React from 'react';
+import { Helmet } from 'react-helmet';
+
+const NotFound = () =>
+       <div>
+               <Helmet>
+                       <title>Not Found</title>
+               </Helmet>
+               <h1>Not Found</h1>
+               <p>Sorry</p>
+       </div>;
+
+export default NotFound;
diff --git a/resources/js/pages/Schedule.js b/resources/js/pages/Schedule.js
deleted file mode 100644 (file)
index 5007739..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-import axios from 'axios';
-import moment from 'moment';
-import React from 'react';
-import { Alert, Button, Container } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-import toastr from 'toastr';
-
-import CanonicalLinks from '../components/common/CanonicalLinks';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import Icon from '../components/common/Icon';
-import ApplyDialog from '../components/episodes/ApplyDialog';
-import Filter from '../components/episodes/Filter';
-import List from '../components/episodes/List';
-import RestreamDialog from '../components/episodes/RestreamDialog';
-import { toggleEventFilter } from '../helpers/Episode';
-import { useUser } from '../hooks/user';
-
-export const Component = () => {
-       const [ahead] = React.useState(14);
-       const [applyAs, setApplyAs] = React.useState('commentary');
-       const [behind] = React.useState(0);
-       const [episodes, setEpisodes] = React.useState([]);
-       const [events, setEvents] = React.useState([]);
-       const [filter, setFilter] = React.useState({});
-       const [restreamChannel, setRestreamChannel] = React.useState(null);
-       const [restreamEpisode, setRestreamEpisode] = React.useState(null);
-       const [showApplyDialog, setShowApplyDialog] = React.useState(false);
-       const [showRestreamDialog, setShowRestreamDialog] = React.useState(false);
-       const [showFilter, setShowFilter] = React.useState(false);
-
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       React.useEffect(() => {
-               const savedFilter = localStorage.getItem('episodes.filter.schedule');
-               if (savedFilter) {
-                       setFilter(JSON.parse(savedFilter));
-               } else {
-                       setFilter(filter => filter ? {} : filter);
-               }
-       }, []);
-
-       const fetchEvents = React.useCallback((controller) => {
-               axios.get(`/api/events`, {
-                       signal: controller.signal,
-                       params: {
-                               after: moment().startOf('day').subtract(1, 'days').toISOString(),
-                               before: moment().startOf('day').add(8, 'days').toISOString(),
-                       },
-               }).then(response => {
-                       const newEvents = (response.data || []).sort(
-                               (a, b) => (a.short || a.title).localeCompare(b.short || b.title)
-                       );
-                       setEvents(newEvents);
-               }).catch(e => {
-                       if (!axios.isCancel(e)) {
-                               console.error(e);
-                       }
-               });
-       });
-
-       React.useEffect(() => {
-               const controller = new AbortController();
-               fetchEvents(controller);
-               const timer = setInterval(() => {
-                       fetchEvents(controller);
-                       clearInterval(timer);
-               }, 15 * 60 * 1000);
-               return () => {
-                       controller.abort();
-               };
-       }, []);
-
-       const updateFilter = React.useCallback(newFilter => {
-               localStorage.setItem('episodes.filter.schedule', JSON.stringify(newFilter));
-               setFilter(newFilter);
-       }, []);
-
-       const invertFilter = React.useCallback(() => {
-               updateFilter(events.reduce((newFilter, event) => {
-                       return toggleEventFilter(events, newFilter, event);
-               }, filter));
-       }, [events, filter]);
-
-       const fetchEpisodes = React.useCallback((controller, ahead, behind, filter) => {
-               axios.get(`/api/episodes`, {
-                       signal: controller.signal,
-                       params: {
-                               after: moment().subtract(2, 'hours').subtract(behind, 'days').toISOString(),
-                               before: moment().add(16, 'hours').add(ahead, 'days').toISOString(),
-                               ...filter,
-                       },
-               }).then(response => {
-                       setEpisodes(response.data || []);
-               }).catch(e => {
-                       if (!axios.isCancel(e)) {
-                               console.error(e);
-                       }
-               });
-       }, []);
-
-       const onAddRestream = React.useCallback(episode => {
-               setRestreamEpisode(episode);
-               setShowRestreamDialog(true);
-       }, []);
-
-       const onAddRestreamSubmit = React.useCallback(async values => {
-               try {
-                       const response = await axios.post(
-                               `/api/episodes/${values.episode_id}/add-restream`, values);
-                       const newEpisode = response.data;
-                       setEpisodes(episodes => episodes.map(episode =>
-                               episode.id === newEpisode.id ? {
-                                       ...episode,
-                                       ...newEpisode,
-                               } : episode
-                       ));
-                       toastr.success(t('episodes.restreamDialog.addSuccess'));
-               } catch (e) {
-                       toastr.error(t('episodes.restreamDialog.addError'));
-                       throw e;
-               }
-               setRestreamEpisode(null);
-               setShowRestreamDialog(false);
-       }, []);
-
-       const onRemoveRestream = React.useCallback(async (episode, channel) => {
-               try {
-                       const response = await axios.post(
-                               `/api/episodes/${episode.id}/remove-restream`, { channel_id: channel.id });
-                       const newEpisode = response.data;
-                       setEpisodes(episodes => episodes.map(episode =>
-                               episode.id === newEpisode.id ? {
-                                       ...episode,
-                                       ...newEpisode,
-                               } : episode
-                       ));
-                       toastr.success(t('episodes.restreamDialog.removeSuccess'));
-                       setRestreamChannel(null);
-                       setRestreamEpisode(null);
-                       setShowRestreamDialog(false);
-               } catch (e) {
-                       toastr.error(t('episodes.restreamDialog.removeError'));
-               }
-       }, []);
-
-       const onEditRestream = React.useCallback((episode, channel) => {
-               setRestreamChannel(channel);
-               setRestreamEpisode(episode);
-               setShowRestreamDialog(true);
-       }, []);
-
-       const editRestream = React.useCallback(async values => {
-               try {
-                       const response = await axios.post(
-                               `/api/episodes/${values.episode_id}/edit-restream`, values);
-                       const newEpisode = response.data;
-                       setEpisodes(episodes => episodes.map(episode =>
-                               episode.id === newEpisode.id ? {
-                                       ...episode,
-                                       ...newEpisode,
-                               } : episode
-                       ));
-                       setRestreamEpisode(episode => ({
-                               ...episode,
-                               ...newEpisode,
-                       }));
-                       const newChannel = newEpisode.channels.find(c => c.id === values.channel_id);
-                       setRestreamChannel(channel => ({
-                               ...channel,
-                               ...newChannel,
-                       }));
-                       toastr.success(t('episodes.restreamDialog.editSuccess'));
-               } catch (e) {
-                       toastr.error(t('episodes.restreamDialog.editError'));
-               }
-       }, []);
-
-       const manageCrew = React.useCallback(async values => {
-               try {
-                       const response = await axios.post(
-                               `/api/episodes/${values.episode_id}/crew-manage`, values);
-                       const newEpisode = response.data;
-                       setEpisodes(episodes => episodes.map(episode =>
-                               episode.id === newEpisode.id ? {
-                                       ...episode,
-                                       ...newEpisode,
-                               } : episode
-                       ));
-                       setRestreamEpisode(episode => ({
-                               ...episode,
-                               ...newEpisode,
-                       }));
-                       const newChannel = newEpisode.channels.find(c => c.id === values.channel_id);
-                       setRestreamChannel(channel => ({
-                               ...channel,
-                               ...newChannel,
-                       }));
-                       toastr.success(t('episodes.restreamDialog.crewSuccess'));
-               } catch (e) {
-                       toastr.error(t('episodes.restreamDialog.crewError'));
-               }
-       }, []);
-
-       const onHideRestreamDialog = React.useCallback(() => {
-               setShowRestreamDialog(false);
-               setRestreamChannel(null);
-               setRestreamEpisode(null);
-       }, []);
-
-       const onApply = React.useCallback((episode, as) => {
-               setShowApplyDialog(true);
-               setRestreamEpisode(episode);
-               setApplyAs(as);
-       }, []);
-
-       const onSubmitApplyDialog = React.useCallback(async values => {
-               try {
-                       const response = await axios.post(
-                               `/api/episodes/${values.episode_id}/crew-signup`, values);
-                       const newEpisode = response.data;
-                       setEpisodes(episodes => episodes.map(episode =>
-                               episode.id === newEpisode.id ? {
-                                       ...episode,
-                                       ...newEpisode,
-                               } : episode
-                       ));
-                       toastr.success(t('episodes.applyDialog.applySuccess'));
-               } catch (e) {
-                       toastr.error(t('episodes.applyDialog.applyError'));
-                       throw e;
-               }
-               setRestreamEpisode(null);
-               setShowApplyDialog(false);
-       }, []);
-
-       const onHideApplyDialog = React.useCallback(() => {
-               setShowApplyDialog(false);
-               setRestreamEpisode(null);
-       }, []);
-
-       React.useEffect(() => {
-               const controller = new AbortController();
-               fetchEpisodes(controller, ahead, behind, filter);
-               const timer = setInterval(() => {
-                       fetchEpisodes(controller, ahead, behind, filter);
-               }, 1.5 * 60 * 1000);
-               return () => {
-                       controller.abort();
-                       clearInterval(timer);
-               };
-       }, [ahead, behind, fetchEpisodes, filter]);
-
-       const toggleFilter = React.useCallback(() => {
-               setShowFilter(show => !show);
-       }, []);
-
-       const filterButtonVariant = React.useMemo(() => {
-               const outline = showFilter ? '' : 'outline-';
-               const filterActive = filter && filter.event && filter.event.length;
-               return `${outline}${filterActive ? 'info' : 'secondary'}`;
-       }, [filter, showFilter]);
-
-       return <Container>
-               <Helmet>
-                       <title>{t('schedule.heading')}</title>
-                       <meta name="description" content={t('schedule.description')} />
-               </Helmet>
-               <CanonicalLinks base="/schedule" />
-               <div className="d-flex align-items-end justify-content-between">
-                       <h1 className="mb-0">{t('schedule.heading')}</h1>
-                       <div className="button-bar">
-                               {showFilter ?
-                                       <Button
-                                               onClick={invertFilter}
-                                               title={t('button.invert')}
-                                               variant="outline-secondary"
-                                       >
-                                               <Icon.INVERT title="" />
-                                       </Button>
-                               : null}
-                               <Button
-                                       onClick={toggleFilter}
-                                       title={t('button.filter')}
-                                       variant={filterButtonVariant}
-                               >
-                                       <Icon.FILTER title="" />
-                               </Button>
-                       </div>
-               </div>
-               {showFilter ?
-                       <div className="my-2">
-                               <Filter events={events} filter={filter} setFilter={updateFilter} />
-                       </div>
-               : null}
-               <ErrorBoundary>
-                       {episodes.length ?
-                               <List
-                                       episodes={episodes}
-                                       onAddRestream={onAddRestream}
-                                       onApply={onApply}
-                                       onEditRestream={onEditRestream}
-                               />
-                       :
-                               <Alert variant="info">
-                                       {t('episodes.empty')}
-                               </Alert>
-                       }
-               </ErrorBoundary>
-               {user ? <>
-                       <ApplyDialog
-                               as={applyAs}
-                               episode={restreamEpisode}
-                               onHide={onHideApplyDialog}
-                               onSubmit={onSubmitApplyDialog}
-                               show={showApplyDialog}
-                       />
-                       <RestreamDialog
-                               channel={restreamChannel}
-                               editRestream={editRestream}
-                               episode={restreamEpisode}
-                               manageCrew={manageCrew}
-                               onRemoveRestream={onRemoveRestream}
-                               onHide={onHideRestreamDialog}
-                               onSubmit={onAddRestreamSubmit}
-                               show={showRestreamDialog}
-                       />
-               </> : null}
-       </Container>;
-};
diff --git a/resources/js/pages/Schedule.jsx b/resources/js/pages/Schedule.jsx
new file mode 100644 (file)
index 0000000..2b6a623
--- /dev/null
@@ -0,0 +1,329 @@
+import axios from 'axios';
+import moment from 'moment';
+import React from 'react';
+import { Alert, Button, Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+import toastr from 'toastr';
+
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import Icon from '../components/common/Icon';
+import ApplyDialog from '../components/episodes/ApplyDialog';
+import Filter from '../components/episodes/Filter';
+import List from '../components/episodes/List';
+import RestreamDialog from '../components/episodes/RestreamDialog';
+import { invertEventFilter, toggleEventFilter } from '../helpers/Episode';
+import { useUser } from '../hooks/user';
+
+export const Component = () => {
+       const [ahead] = React.useState(14);
+       const [applyAs, setApplyAs] = React.useState('commentary');
+       const [behind] = React.useState(0);
+       const [episodes, setEpisodes] = React.useState([]);
+       const [events, setEvents] = React.useState([]);
+       const [filter, setFilter] = React.useState({});
+       const [restreamChannel, setRestreamChannel] = React.useState(null);
+       const [restreamEpisode, setRestreamEpisode] = React.useState(null);
+       const [showApplyDialog, setShowApplyDialog] = React.useState(false);
+       const [showRestreamDialog, setShowRestreamDialog] = React.useState(false);
+       const [showFilter, setShowFilter] = React.useState(false);
+
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       React.useEffect(() => {
+               const savedFilter = localStorage.getItem('episodes.filter.schedule');
+               if (savedFilter) {
+                       setFilter(JSON.parse(savedFilter));
+               } else {
+                       setFilter(filter => filter ? {} : filter);
+               }
+       }, []);
+
+       const fetchEvents = React.useCallback((controller) => {
+               axios.get(`/api/events`, {
+                       signal: controller.signal,
+                       params: {
+                               after: moment().startOf('day').subtract(1, 'days').toISOString(),
+                               before: moment().startOf('day').add(8, 'days').toISOString(),
+                       },
+               }).then(response => {
+                       const newEvents = (response.data || []).sort(
+                               (a, b) => (a.short || a.title).localeCompare(b.short || b.title)
+                       );
+                       setEvents(newEvents);
+               }).catch(e => {
+                       if (!axios.isCancel(e)) {
+                               console.error(e);
+                       }
+               });
+       });
+
+       React.useEffect(() => {
+               const controller = new AbortController();
+               fetchEvents(controller);
+               const timer = setInterval(() => {
+                       fetchEvents(controller);
+                       clearInterval(timer);
+               }, 15 * 60 * 1000);
+               return () => {
+                       controller.abort();
+               };
+       }, []);
+
+       const updateFilter = React.useCallback(newFilter => {
+               localStorage.setItem('episodes.filter.schedule', JSON.stringify(newFilter));
+               setFilter(newFilter);
+       }, []);
+
+       const invertFilter = React.useCallback(() => {
+               updateFilter(invertEventFilter(filter));
+       }, [filter, updateFilter]);
+
+       const fetchEpisodes = React.useCallback((controller, ahead, behind, filter) => {
+               axios.get(`/api/episodes`, {
+                       signal: controller.signal,
+                       params: {
+                               after: moment().subtract(2, 'hours').subtract(behind, 'days').toISOString(),
+                               before: moment().add(16, 'hours').add(ahead, 'days').toISOString(),
+                               ...filter,
+                       },
+               }).then(response => {
+                       setEpisodes(response.data || []);
+               }).catch(e => {
+                       if (!axios.isCancel(e)) {
+                               console.error(e);
+                       }
+               });
+       }, []);
+
+       const onAddRestream = React.useCallback(episode => {
+               setRestreamEpisode(episode);
+               setShowRestreamDialog(true);
+       }, []);
+
+       const onAddRestreamSubmit = React.useCallback(async values => {
+               try {
+                       const response = await axios.post(
+                               `/api/episodes/${values.episode_id}/add-restream`, values);
+                       const newEpisode = response.data;
+                       setEpisodes(episodes => episodes.map(episode =>
+                               episode.id === newEpisode.id ? {
+                                       ...episode,
+                                       ...newEpisode,
+                               } : episode
+                       ));
+                       toastr.success(t('episodes.restreamDialog.addSuccess'));
+               } catch (e) {
+                       toastr.error(t('episodes.restreamDialog.addError'));
+                       throw e;
+               }
+               setRestreamEpisode(null);
+               setShowRestreamDialog(false);
+       }, []);
+
+       const onRemoveRestream = React.useCallback(async (episode, channel) => {
+               try {
+                       const response = await axios.post(
+                               `/api/episodes/${episode.id}/remove-restream`, { channel_id: channel.id });
+                       const newEpisode = response.data;
+                       setEpisodes(episodes => episodes.map(episode =>
+                               episode.id === newEpisode.id ? {
+                                       ...episode,
+                                       ...newEpisode,
+                               } : episode
+                       ));
+                       toastr.success(t('episodes.restreamDialog.removeSuccess'));
+                       setRestreamChannel(null);
+                       setRestreamEpisode(null);
+                       setShowRestreamDialog(false);
+               } catch (e) {
+                       toastr.error(t('episodes.restreamDialog.removeError'));
+               }
+       }, []);
+
+       const onEditRestream = React.useCallback((episode, channel) => {
+               setRestreamChannel(channel);
+               setRestreamEpisode(episode);
+               setShowRestreamDialog(true);
+       }, []);
+
+       const editRestream = React.useCallback(async values => {
+               try {
+                       const response = await axios.post(
+                               `/api/episodes/${values.episode_id}/edit-restream`, values);
+                       const newEpisode = response.data;
+                       setEpisodes(episodes => episodes.map(episode =>
+                               episode.id === newEpisode.id ? {
+                                       ...episode,
+                                       ...newEpisode,
+                               } : episode
+                       ));
+                       setRestreamEpisode(episode => ({
+                               ...episode,
+                               ...newEpisode,
+                       }));
+                       const newChannel = newEpisode.channels.find(c => c.id === values.channel_id);
+                       setRestreamChannel(channel => ({
+                               ...channel,
+                               ...newChannel,
+                       }));
+                       toastr.success(t('episodes.restreamDialog.editSuccess'));
+               } catch (e) {
+                       toastr.error(t('episodes.restreamDialog.editError'));
+               }
+       }, []);
+
+       const manageCrew = React.useCallback(async values => {
+               try {
+                       const response = await axios.post(
+                               `/api/episodes/${values.episode_id}/crew-manage`, values);
+                       const newEpisode = response.data;
+                       setEpisodes(episodes => episodes.map(episode =>
+                               episode.id === newEpisode.id ? {
+                                       ...episode,
+                                       ...newEpisode,
+                               } : episode
+                       ));
+                       setRestreamEpisode(episode => ({
+                               ...episode,
+                               ...newEpisode,
+                       }));
+                       const newChannel = newEpisode.channels.find(c => c.id === values.channel_id);
+                       setRestreamChannel(channel => ({
+                               ...channel,
+                               ...newChannel,
+                       }));
+                       toastr.success(t('episodes.restreamDialog.crewSuccess'));
+               } catch (e) {
+                       toastr.error(t('episodes.restreamDialog.crewError'));
+               }
+       }, []);
+
+       const onHideRestreamDialog = React.useCallback(() => {
+               setShowRestreamDialog(false);
+               setRestreamChannel(null);
+               setRestreamEpisode(null);
+       }, []);
+
+       const onApply = React.useCallback((episode, as) => {
+               setShowApplyDialog(true);
+               setRestreamEpisode(episode);
+               setApplyAs(as);
+       }, []);
+
+       const onSubmitApplyDialog = React.useCallback(async values => {
+               try {
+                       const response = await axios.post(
+                               `/api/episodes/${values.episode_id}/crew-signup`, values);
+                       const newEpisode = response.data;
+                       setEpisodes(episodes => episodes.map(episode =>
+                               episode.id === newEpisode.id ? {
+                                       ...episode,
+                                       ...newEpisode,
+                               } : episode
+                       ));
+                       toastr.success(t('episodes.applyDialog.applySuccess'));
+               } catch (e) {
+                       toastr.error(t('episodes.applyDialog.applyError'));
+                       throw e;
+               }
+               setRestreamEpisode(null);
+               setShowApplyDialog(false);
+       }, []);
+
+       const onHideApplyDialog = React.useCallback(() => {
+               setShowApplyDialog(false);
+               setRestreamEpisode(null);
+       }, []);
+
+       React.useEffect(() => {
+               const controller = new AbortController();
+               fetchEpisodes(controller, ahead, behind, filter);
+               const timer = setInterval(() => {
+                       fetchEpisodes(controller, ahead, behind, filter);
+               }, 1.5 * 60 * 1000);
+               return () => {
+                       controller.abort();
+                       clearInterval(timer);
+               };
+       }, [ahead, behind, fetchEpisodes, filter]);
+
+       const toggleFilter = React.useCallback(() => {
+               setShowFilter(show => !show);
+       }, []);
+
+       const filterButtonVariant = React.useMemo(() => {
+               const outline = showFilter ? '' : 'outline-';
+               const filterActive = filter && filter.event && filter.event.length;
+               return `${outline}${filterActive ? 'info' : 'secondary'}`;
+       }, [filter, showFilter]);
+
+       return <Container>
+               <Helmet>
+                       <title>{t('schedule.heading')}</title>
+                       <meta name="description" content={t('schedule.description')} />
+               </Helmet>
+               <CanonicalLinks base="/schedule" />
+               <div className="d-flex align-items-end justify-content-between">
+                       <h1 className="mb-0">{t('schedule.heading')}</h1>
+                       <div className="button-bar">
+                               {showFilter ?
+                                       <Button
+                                               onClick={invertFilter}
+                                               title={t('button.invert')}
+                                               variant="outline-secondary"
+                                       >
+                                               <Icon.INVERT title="" />
+                                       </Button>
+                               : null}
+                               <Button
+                                       onClick={toggleFilter}
+                                       title={t('button.filter')}
+                                       variant={filterButtonVariant}
+                               >
+                                       <Icon.FILTER title="" />
+                               </Button>
+                       </div>
+               </div>
+               {showFilter ?
+                       <div className="my-2">
+                               <Filter events={events} filter={filter} setFilter={updateFilter} />
+                       </div>
+               : null}
+               <ErrorBoundary>
+                       {episodes.length ?
+                               <List
+                                       episodes={episodes}
+                                       onAddRestream={onAddRestream}
+                                       onApply={onApply}
+                                       onEditRestream={onEditRestream}
+                               />
+                       :
+                               <Alert variant="info">
+                                       {t('episodes.empty')}
+                               </Alert>
+                       }
+               </ErrorBoundary>
+               {user ? <>
+                       <ApplyDialog
+                               as={applyAs}
+                               episode={restreamEpisode}
+                               onHide={onHideApplyDialog}
+                               onSubmit={onSubmitApplyDialog}
+                               show={showApplyDialog}
+                       />
+                       <RestreamDialog
+                               channel={restreamChannel}
+                               editRestream={editRestream}
+                               episode={restreamEpisode}
+                               manageCrew={manageCrew}
+                               onRemoveRestream={onRemoveRestream}
+                               onHide={onHideRestreamDialog}
+                               onSubmit={onAddRestreamSubmit}
+                               show={showRestreamDialog}
+                       />
+               </> : null}
+       </Container>;
+};
diff --git a/resources/js/pages/Technique.js b/resources/js/pages/Technique.js
deleted file mode 100644 (file)
index b2da417..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React, { useEffect, useState } from 'react';
-import { Helmet } from 'react-helmet';
-import { withTranslation } from 'react-i18next';
-import { useParams } from 'react-router-dom';
-import toastr from 'toastr';
-
-import CanonicalLinks from '../components/common/CanonicalLinks';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import ErrorMessage from '../components/common/ErrorMessage';
-import Loading from '../components/common/Loading';
-import NotFound from '../pages/NotFound';
-import Detail from '../components/techniques/Detail';
-import Dialog from '../components/techniques/Dialog';
-import {
-       mayEditContent,
-} from '../helpers/permissions';
-import { getLanguages, getMatchedLocale, getTranslation } from '../helpers/Technique';
-import { useUser } from '../hooks/user';
-import i18n from '../i18n';
-
-const Technique = ({ basepath, type }) => {
-       const params = useParams();
-       const { name } = params;
-       const { user } = useUser();
-
-       const [error, setError] = useState(null);
-       const [loading, setLoading] = useState(true);
-       const [technique, setTechnique] = useState(null);
-
-       const [editContent, setEditContent] = useState(null);
-       const [showContentDialog, setShowContentDialog] = useState(false);
-
-       const actions = React.useMemo(() => ({
-               editContent: mayEditContent(user) ? content => {
-                       setEditContent(content);
-                       setShowContentDialog(true);
-               } : null,
-       }), [user]);
-
-       const saveContent = React.useCallback(async values => {
-               try {
-                       const response = await axios.put(`/api/content/${values.id}`, {
-                               parent_id: technique.id,
-                               ...values,
-                       });
-                       toastr.success(i18n.t('content.saveSuccess'));
-                       setTechnique(response.data);
-                       setShowContentDialog(false);
-               } catch (e) {
-                       toastr.error(i18n.t('content.saveError'));
-               }
-       }, [technique && technique.id]);
-
-       useEffect(() => {
-               const ctrl = new AbortController();
-               setLoading(true);
-               axios
-                       .get(`/api/pages/${type}/${name}`, { signal: ctrl.signal })
-                       .then(response => {
-                               setError(null);
-                               setLoading(false);
-                               setTechnique(response.data);
-                       })
-                       .catch(error => {
-                               setError(error);
-                               setLoading(false);
-                               setTechnique(null);
-                       });
-               return () => {
-                       ctrl.abort();
-               };
-       }, [name, type]);
-
-       if (loading) {
-               return <Loading />;
-       }
-
-       if (error) {
-               return <ErrorMessage error={error} />;
-       }
-
-       if (!technique) {
-               return <NotFound />;
-       }
-
-       return <ErrorBoundary>
-               <Helmet>
-                       <title>{getTranslation(technique, 'title', i18n.language)}</title>
-                       <meta name="description" content={getTranslation(technique, 'short', i18n.language)} />
-               </Helmet>
-               {technique.image ? <Helmet>
-                       <meta property="og:image" content={technique.image} />
-                       <meta property="twitter:image" content={technique.image} />
-               </Helmet> : null}
-               {!technique.image && technique.gif ? <Helmet>
-                       <meta property="og:image" content={technique.gif} />
-                       <meta property="twitter:image" content={technique.gif} />
-               </Helmet> : null}
-               <CanonicalLinks
-                       base={`/${basepath}/${technique.name}`}
-                       lang={getMatchedLocale(technique, i18n.language)}
-                       langs={getLanguages(technique)}
-               />
-               <Detail actions={actions} technique={technique} />
-               <Dialog
-                       content={editContent}
-                       language={i18n.language}
-                       onHide={() => { setShowContentDialog(false); }}
-                       onSubmit={saveContent}
-                       show={showContentDialog}
-               />
-       </ErrorBoundary>;
-};
-
-Technique.propTypes = {
-       basepath: PropTypes.string,
-       type: PropTypes.string,
-};
-
-export default withTranslation()(Technique);
diff --git a/resources/js/pages/Technique.jsx b/resources/js/pages/Technique.jsx
new file mode 100644 (file)
index 0000000..b2da417
--- /dev/null
@@ -0,0 +1,122 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React, { useEffect, useState } from 'react';
+import { Helmet } from 'react-helmet';
+import { withTranslation } from 'react-i18next';
+import { useParams } from 'react-router-dom';
+import toastr from 'toastr';
+
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+import NotFound from '../pages/NotFound';
+import Detail from '../components/techniques/Detail';
+import Dialog from '../components/techniques/Dialog';
+import {
+       mayEditContent,
+} from '../helpers/permissions';
+import { getLanguages, getMatchedLocale, getTranslation } from '../helpers/Technique';
+import { useUser } from '../hooks/user';
+import i18n from '../i18n';
+
+const Technique = ({ basepath, type }) => {
+       const params = useParams();
+       const { name } = params;
+       const { user } = useUser();
+
+       const [error, setError] = useState(null);
+       const [loading, setLoading] = useState(true);
+       const [technique, setTechnique] = useState(null);
+
+       const [editContent, setEditContent] = useState(null);
+       const [showContentDialog, setShowContentDialog] = useState(false);
+
+       const actions = React.useMemo(() => ({
+               editContent: mayEditContent(user) ? content => {
+                       setEditContent(content);
+                       setShowContentDialog(true);
+               } : null,
+       }), [user]);
+
+       const saveContent = React.useCallback(async values => {
+               try {
+                       const response = await axios.put(`/api/content/${values.id}`, {
+                               parent_id: technique.id,
+                               ...values,
+                       });
+                       toastr.success(i18n.t('content.saveSuccess'));
+                       setTechnique(response.data);
+                       setShowContentDialog(false);
+               } catch (e) {
+                       toastr.error(i18n.t('content.saveError'));
+               }
+       }, [technique && technique.id]);
+
+       useEffect(() => {
+               const ctrl = new AbortController();
+               setLoading(true);
+               axios
+                       .get(`/api/pages/${type}/${name}`, { signal: ctrl.signal })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setTechnique(response.data);
+                       })
+                       .catch(error => {
+                               setError(error);
+                               setLoading(false);
+                               setTechnique(null);
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [name, type]);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       if (!technique) {
+               return <NotFound />;
+       }
+
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>{getTranslation(technique, 'title', i18n.language)}</title>
+                       <meta name="description" content={getTranslation(technique, 'short', i18n.language)} />
+               </Helmet>
+               {technique.image ? <Helmet>
+                       <meta property="og:image" content={technique.image} />
+                       <meta property="twitter:image" content={technique.image} />
+               </Helmet> : null}
+               {!technique.image && technique.gif ? <Helmet>
+                       <meta property="og:image" content={technique.gif} />
+                       <meta property="twitter:image" content={technique.gif} />
+               </Helmet> : null}
+               <CanonicalLinks
+                       base={`/${basepath}/${technique.name}`}
+                       lang={getMatchedLocale(technique, i18n.language)}
+                       langs={getLanguages(technique)}
+               />
+               <Detail actions={actions} technique={technique} />
+               <Dialog
+                       content={editContent}
+                       language={i18n.language}
+                       onHide={() => { setShowContentDialog(false); }}
+                       onSubmit={saveContent}
+                       show={showContentDialog}
+               />
+       </ErrorBoundary>;
+};
+
+Technique.propTypes = {
+       basepath: PropTypes.string,
+       type: PropTypes.string,
+};
+
+export default withTranslation()(Technique);
diff --git a/resources/js/pages/Techniques.js b/resources/js/pages/Techniques.js
deleted file mode 100644 (file)
index 0c5d5b0..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-import axios from 'axios';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { Helmet } from 'react-helmet';
-import { withTranslation } from 'react-i18next';
-
-import NotFound from './NotFound';
-import CanonicalLinks from '../components/common/CanonicalLinks';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import ErrorMessage from '../components/common/ErrorMessage';
-import Loading from '../components/common/Loading';
-import Overview from '../components/techniques/Overview';
-import { compareTranslation } from '../helpers/Technique';
-import i18n from '../i18n';
-
-const Techniques = ({ namespace, type }) => {
-       const [error, setError] = React.useState(null);
-       const [filter, setFilter] = React.useState({});
-       const [loading, setLoading] = React.useState(true);
-       const [techniques, setTechniques] = React.useState([]);
-
-       React.useEffect(() => {
-               const savedFilter = localStorage.getItem(`content.filter.${type}`);
-               if (savedFilter) {
-                       setFilter(JSON.parse(savedFilter));
-               } else {
-                       setFilter(filter => filter ? {} : filter);
-               }
-       }, [type]);
-
-       const updateFilter = React.useCallback(newFilter => {
-               localStorage.setItem(`content.filter.${type}`, JSON.stringify(newFilter));
-               setFilter(newFilter);
-       }, [type]);
-
-       React.useEffect(() => {
-               const ctrl = new AbortController();
-               if (!techniques.length) {
-                       setLoading(true);
-               }
-               axios
-                       .get(`/api/pages/${type}`, {
-                               params: filter,
-                               signal: ctrl.signal
-                       })
-                       .then(response => {
-                               setError(null);
-                               setLoading(false);
-                               setTechniques(response.data.sort(compareTranslation('title', i18n.language)));
-                       })
-                       .catch(error => {
-                               if (!axios.isCancel(error)) {
-                                       setError(error);
-                                       setLoading(false);
-                                       setTechniques([]);
-                               }
-                       });
-               return () => {
-                       ctrl.abort();
-               };
-       }, [filter, namespace, type]);
-
-       React.useEffect(() => {
-               setTechniques(t => [...t].sort(compareTranslation('title', i18n.language)));
-       }, [namespace, i18n.language]);
-
-       if (loading) {
-               return <Loading />;
-       }
-
-       if (error) {
-               return <ErrorMessage error={error} />;
-       }
-
-       if (!techniques || !techniques.length) {
-               return <NotFound />;
-       }
-
-       return <ErrorBoundary>
-               <Helmet>
-                       <title>{i18n.t(`${namespace}.heading`)}</title>
-                       <meta name="description" content={i18n.t(`${namespace}.description`)} />
-               </Helmet>
-               <CanonicalLinks base="/tech" />
-               <Overview
-                       filter={filter}
-                       namespace={namespace}
-                       setFilter={updateFilter}
-                       techniques={techniques}
-                       type={type}
-               />
-       </ErrorBoundary>;
-};
-
-Techniques.propTypes = {
-       namespace: PropTypes.string,
-       type: PropTypes.string,
-};
-
-export default withTranslation()(Techniques);
diff --git a/resources/js/pages/Techniques.jsx b/resources/js/pages/Techniques.jsx
new file mode 100644 (file)
index 0000000..0c5d5b0
--- /dev/null
@@ -0,0 +1,100 @@
+import axios from 'axios';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Helmet } from 'react-helmet';
+import { withTranslation } from 'react-i18next';
+
+import NotFound from './NotFound';
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+import Overview from '../components/techniques/Overview';
+import { compareTranslation } from '../helpers/Technique';
+import i18n from '../i18n';
+
+const Techniques = ({ namespace, type }) => {
+       const [error, setError] = React.useState(null);
+       const [filter, setFilter] = React.useState({});
+       const [loading, setLoading] = React.useState(true);
+       const [techniques, setTechniques] = React.useState([]);
+
+       React.useEffect(() => {
+               const savedFilter = localStorage.getItem(`content.filter.${type}`);
+               if (savedFilter) {
+                       setFilter(JSON.parse(savedFilter));
+               } else {
+                       setFilter(filter => filter ? {} : filter);
+               }
+       }, [type]);
+
+       const updateFilter = React.useCallback(newFilter => {
+               localStorage.setItem(`content.filter.${type}`, JSON.stringify(newFilter));
+               setFilter(newFilter);
+       }, [type]);
+
+       React.useEffect(() => {
+               const ctrl = new AbortController();
+               if (!techniques.length) {
+                       setLoading(true);
+               }
+               axios
+                       .get(`/api/pages/${type}`, {
+                               params: filter,
+                               signal: ctrl.signal
+                       })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setTechniques(response.data.sort(compareTranslation('title', i18n.language)));
+                       })
+                       .catch(error => {
+                               if (!axios.isCancel(error)) {
+                                       setError(error);
+                                       setLoading(false);
+                                       setTechniques([]);
+                               }
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [filter, namespace, type]);
+
+       React.useEffect(() => {
+               setTechniques(t => [...t].sort(compareTranslation('title', i18n.language)));
+       }, [namespace, i18n.language]);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       if (!techniques || !techniques.length) {
+               return <NotFound />;
+       }
+
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>{i18n.t(`${namespace}.heading`)}</title>
+                       <meta name="description" content={i18n.t(`${namespace}.description`)} />
+               </Helmet>
+               <CanonicalLinks base="/tech" />
+               <Overview
+                       filter={filter}
+                       namespace={namespace}
+                       setFilter={updateFilter}
+                       techniques={techniques}
+                       type={type}
+               />
+       </ErrorBoundary>;
+};
+
+Techniques.propTypes = {
+       namespace: PropTypes.string,
+       type: PropTypes.string,
+};
+
+export default withTranslation()(Techniques);
diff --git a/resources/js/pages/Tournament.js b/resources/js/pages/Tournament.js
deleted file mode 100644 (file)
index ecaab6c..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-import axios from 'axios';
-import React, { useEffect, useState } from 'react';
-import { Helmet } from 'react-helmet';
-import { useParams } from 'react-router-dom';
-
-import CanonicalLinks from '../components/common/CanonicalLinks';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import ErrorMessage from '../components/common/ErrorMessage';
-import Loading from '../components/common/Loading';
-import NotFound from '../pages/NotFound';
-import Detail from '../components/tournament/Detail';
-import {
-       canLoadMoreRounds,
-       getLastRound,
-       patchApplication,
-       patchParticipant,
-       patchResult,
-       patchRound,
-       patchUser,
-       removeApplication,
-       sortParticipants,
-} from '../helpers/Tournament';
-
-export const Component = () => {
-       const params = useParams();
-       const { id } = params;
-
-       const [error, setError] = useState(null);
-       const [loading, setLoading] = useState(true);
-       const [tournament, setTournament] = useState(null);
-
-       useEffect(() => {
-               const ctrl = new AbortController();
-               setLoading(true);
-               axios
-                       .get(`/api/tournaments/${id}`, { signal: ctrl.signal })
-                       .then(response => {
-                               setError(null);
-                               setLoading(false);
-                               setTournament(sortParticipants(response.data));
-                       })
-                       .catch(error => {
-                               setError(error);
-                               setLoading(false);
-                               setTournament(null);
-                       });
-               return () => {
-                       ctrl.abort();
-               };
-       }, [id]);
-
-       useEffect(() => {
-               window.Echo.channel(`Tournament.${id}`)
-                       .listen('ApplicationAdded', e => {
-                               if (e.application) {
-                                       setTournament(tournament => patchApplication(tournament, e.application));
-                               }
-                       })
-                       .listen('ApplicationChanged', e => {
-                               if (e.application) {
-                                       setTournament(tournament => patchApplication(tournament, e.application));
-                               }
-                       })
-                       .listen('ApplicationRemoved', e => {
-                               if (e.application_id) {
-                                       setTournament(tournament => removeApplication(tournament, e.application_id));
-                               }
-                       })
-                       .listen('ParticipantChanged', e => {
-                               if (e.participant) {
-                                       setTournament(tournament => patchParticipant(tournament, e.participant));
-                               }
-                       })
-                       .listen('ResultChanged', e => {
-                               if (e.result) {
-                                       setTournament(tournament => patchResult(tournament, e.result));
-                               }
-                       })
-                       .listen('RoundAdded', e => {
-                               if (e.round) {
-                                       setTournament(tournament => ({
-                                               ...tournament,
-                                               rounds: [e.round, ...tournament.rounds],
-                                       }));
-                               }
-                       })
-                       .listen('RoundChanged', e => {
-                               if (e.round) {
-                                       setTournament(tournament => patchRound(tournament, e.round));
-                               }
-                       })
-                       .listen('TournamentChanged', e => {
-                               if (e.tournament) {
-                                       setTournament(tournament => ({ ...tournament, ...e.tournament }));
-                               }
-                       });
-               return () => {
-                       window.Echo.leave(`Tournament.${id}`);
-               };
-       }, [id]);
-
-       const moreRounds = React.useCallback(async () => {
-               const last_round = getLastRound(tournament);
-               if (!last_round) return;
-               console.log(last_round);
-               const last_known = last_round.number;
-               const rsp = await axios.get(
-                       `/api/tournaments/${id}/more-rounds`,
-                       { params: { last_known } },
-               );
-               setTournament(tournament => ({
-                       ...tournament,
-                       rounds: [...tournament.rounds, ...rsp.data],
-               }));
-       }, [id, tournament]);
-
-       useEffect(() => {
-               const cb = (e) => {
-                       if (e.user) {
-                               setTournament(tournament => patchUser(tournament, e.user));
-                       }
-               };
-               window.Echo.channel('App.Control')
-                       .listen('UserChanged', cb);
-               return () => {
-                       window.Echo.channel('App.Control')
-                               .stopListening('UserChanged', cb);
-               };
-       }, []);
-
-       if (loading) {
-               return <Loading />;
-       }
-
-       if (error) {
-               return <ErrorMessage error={error} />;
-       }
-
-       if (!tournament) {
-               return <NotFound />;
-       }
-
-       const addRound = async () => {
-               await axios.post('/api/rounds', { tournament_id: tournament.id });
-       };
-
-       return <ErrorBoundary>
-               <Helmet>
-                       <title>{tournament.title}</title>
-               </Helmet>
-               <CanonicalLinks base={`/tournaments/${tournament.id}`} />
-               <Detail
-                       addRound={addRound}
-                       moreRounds={canLoadMoreRounds(tournament) ? moreRounds : null}
-                       tournament={tournament}
-               />
-       </ErrorBoundary>;
-};
diff --git a/resources/js/pages/Tournament.jsx b/resources/js/pages/Tournament.jsx
new file mode 100644 (file)
index 0000000..661eaa7
--- /dev/null
@@ -0,0 +1,221 @@
+import axios from 'axios';
+import React, { useEffect, useState } from 'react';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+import { useParams } from 'react-router-dom';
+import toastr from 'toastr';
+
+import NotFound from './NotFound';
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+import Dialog from '../components/techniques/Dialog';
+import Detail from '../components/tournament/Detail';
+import {
+       mayEditContent,
+} from '../helpers/permissions';
+import { getTranslation } from '../helpers/Technique';
+import {
+       canLoadMoreRounds,
+       getLastRound,
+       patchApplication,
+       patchParticipant,
+       patchResult,
+       patchRound,
+       patchUser,
+       removeApplication,
+       sortParticipants,
+} from '../helpers/Tournament';
+import { useUser } from '../hooks/user';
+import i18n from '../i18n';
+
+export const Component = () => {
+       const params = useParams();
+       const { id } = params;
+       const { user } = useUser();
+       const { t } = useTranslation();
+
+       const [error, setError] = useState(null);
+       const [loading, setLoading] = useState(true);
+       const [tournament, setTournament] = useState(null);
+
+       const [editContent, setEditContent] = React.useState(null);
+       const [showContentDialog, setShowContentDialog] = React.useState(false);
+
+       useEffect(() => {
+               const ctrl = new AbortController();
+               setLoading(true);
+               axios
+                       .get(`/api/tournaments/${id}`, { signal: ctrl.signal })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setTournament(sortParticipants(response.data));
+                       })
+                       .catch(error => {
+                               setError(error);
+                               setLoading(false);
+                               setTournament(null);
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [id]);
+
+       useEffect(() => {
+               window.Echo.channel(`Tournament.${id}`)
+                       .listen('ApplicationAdded', e => {
+                               if (e.application) {
+                                       setTournament(tournament => patchApplication(tournament, e.application));
+                               }
+                       })
+                       .listen('ApplicationChanged', e => {
+                               if (e.application) {
+                                       setTournament(tournament => patchApplication(tournament, e.application));
+                               }
+                       })
+                       .listen('ApplicationRemoved', e => {
+                               if (e.application_id) {
+                                       setTournament(tournament => removeApplication(tournament, e.application_id));
+                               }
+                       })
+                       .listen('ParticipantChanged', e => {
+                               if (e.participant) {
+                                       setTournament(tournament => patchParticipant(tournament, e.participant));
+                               }
+                       })
+                       .listen('ResultChanged', e => {
+                               if (e.result) {
+                                       setTournament(tournament => patchResult(tournament, e.result));
+                               }
+                       })
+                       .listen('RoundAdded', e => {
+                               if (e.round) {
+                                       setTournament(tournament => ({
+                                               ...tournament,
+                                               rounds: [e.round, ...tournament.rounds],
+                                       }));
+                               }
+                       })
+                       .listen('RoundChanged', e => {
+                               if (e.round) {
+                                       setTournament(tournament => patchRound(tournament, e.round));
+                               }
+                       })
+                       .listen('.RoundDeleted', e => {
+                               if (e.model) {
+                                       setTournament(tournament => ({
+                                               ...tournament,
+                                               rounds: tournament.rounds.filter((r) => r.id !== e.model.id),
+                                       }));
+                               }
+                       })
+                       .listen('TournamentChanged', e => {
+                               if (e.tournament) {
+                                       setTournament(tournament => ({ ...tournament, ...e.tournament }));
+                               }
+                       });
+               return () => {
+                       window.Echo.leave(`Tournament.${id}`);
+               };
+       }, [id]);
+
+       const addRound = React.useCallback(async () => {
+               await axios.post('/api/rounds', { tournament_id: id });
+       }, [id]);
+
+       const moreRounds = React.useCallback(async () => {
+               const last_round = getLastRound(tournament);
+               if (!last_round) return;
+               const last_known = last_round.number;
+               const rsp = await axios.get(
+                       `/api/tournaments/${id}/more-rounds`,
+                       { params: { last_known } },
+               );
+               setTournament(tournament => ({
+                       ...tournament,
+                       rounds: [...tournament.rounds, ...rsp.data],
+               }));
+       }, [id, tournament]);
+
+       const saveContent = React.useCallback(async values => {
+               try {
+                       const response = await axios.put(`/api/content/${values.id}`, {
+                               parent_id: event.description_id,
+                               ...values,
+                       });
+                       toastr.success(t('content.saveSuccess'));
+                       setTournament(tournament => ({
+                               ...tournament,
+                               description: response.data,
+                       }));
+                       setShowContentDialog(false);
+               } catch (e) {
+                       toastr.error(t('content.saveError', e));
+               }
+       }, [tournament && tournament.description_id]);
+
+       const actions = React.useMemo(() => ({
+               addRound,
+               editContent: mayEditContent(user) ? content => {
+                       setEditContent(content);
+                       setShowContentDialog(true);
+               } : null,
+               moreRounds: canLoadMoreRounds(tournament) ? moreRounds : null,
+       }), [addRound, moreRounds, tournament, user]);
+
+       useEffect(() => {
+               const cb = (e) => {
+                       if (e.user) {
+                               setTournament(tournament => patchUser(tournament, e.user));
+                       }
+               };
+               window.Echo.channel('App.Control')
+                       .listen('UserChanged', cb);
+               return () => {
+                       window.Echo.channel('App.Control')
+                               .stopListening('UserChanged', cb);
+               };
+       }, []);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       if (!tournament) {
+               return <NotFound />;
+       }
+
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>
+                               {(tournament.description
+                                       && getTranslation(tournament.description, 'title', i18n.language))
+                                       || tournament.title}
+                       </title>
+               </Helmet>
+               {tournament.description ? <Helmet>
+                       <meta
+                               name="description"
+                               content={getTranslation(tournament.description, 'short', i18n.language)}
+                       />
+               </Helmet> : null}
+               <CanonicalLinks base={`/tournaments/${tournament.id}`} />
+               <Detail
+                       actions={actions}
+                       tournament={tournament}
+               />
+               <Dialog
+                       content={editContent}
+                       language={i18n.language}
+                       onHide={() => { setShowContentDialog(false); }}
+                       onSubmit={saveContent}
+                       show={showContentDialog}
+               />
+       </ErrorBoundary>;
+};
diff --git a/resources/js/pages/Tracker.js b/resources/js/pages/Tracker.js
deleted file mode 100644 (file)
index eccd766..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import { Helmet } from 'react-helmet';
-
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import Tracker from '../components/tracker';
-import { TrackerProvider } from '../hooks/tracker';
-
-export const Component = () => {
-       return <ErrorBoundary>
-               <Helmet>
-                       <title>Tracker</title>
-               </Helmet>
-               <TrackerProvider>
-                       <Tracker />
-               </TrackerProvider>
-       </ErrorBoundary>;
-};
diff --git a/resources/js/pages/Tracker.jsx b/resources/js/pages/Tracker.jsx
new file mode 100644 (file)
index 0000000..eccd766
--- /dev/null
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Helmet } from 'react-helmet';
+
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import Tracker from '../components/tracker';
+import { TrackerProvider } from '../hooks/tracker';
+
+export const Component = () => {
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>Tracker</title>
+               </Helmet>
+               <TrackerProvider>
+                       <Tracker />
+               </TrackerProvider>
+       </ErrorBoundary>;
+};
diff --git a/resources/js/pages/TwitchBot.js b/resources/js/pages/TwitchBot.js
deleted file mode 100644 (file)
index de13f7f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import { Alert, Container } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-
-import Controls from '../components/twitch-bot/Controls';
-import { mayManageTwitchBot } from '../helpers/permissions';
-import { useUser } from '../hooks/user';
-
-export const Component = () => {
-       const { t } = useTranslation();
-       const { user } = useUser();
-
-       return <Container>
-               <h1>{t('twitchBot.heading')}</h1>
-               <Helmet>
-                       <title>{t('twitchBot.heading')}</title>
-               </Helmet>
-               {mayManageTwitchBot(user) ? <>
-                       <h2>{t('twitchBot.controls')}</h2>
-                       <Controls />
-               </> :
-                       <Alert variant="info">
-                               {t('twitchBot.noManagePermission')}
-                       </Alert>
-               }
-       </Container>;
-};
diff --git a/resources/js/pages/TwitchBot.jsx b/resources/js/pages/TwitchBot.jsx
new file mode 100644 (file)
index 0000000..de13f7f
--- /dev/null
@@ -0,0 +1,28 @@
+import React from 'react';
+import { Alert, Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+
+import Controls from '../components/twitch-bot/Controls';
+import { mayManageTwitchBot } from '../helpers/permissions';
+import { useUser } from '../hooks/user';
+
+export const Component = () => {
+       const { t } = useTranslation();
+       const { user } = useUser();
+
+       return <Container>
+               <h1>{t('twitchBot.heading')}</h1>
+               <Helmet>
+                       <title>{t('twitchBot.heading')}</title>
+               </Helmet>
+               {mayManageTwitchBot(user) ? <>
+                       <h2>{t('twitchBot.controls')}</h2>
+                       <Controls />
+               </> :
+                       <Alert variant="info">
+                               {t('twitchBot.noManagePermission')}
+                       </Alert>
+               }
+       </Container>;
+};
diff --git a/resources/js/pages/TwitchLegal.js b/resources/js/pages/TwitchLegal.js
deleted file mode 100644 (file)
index 197a5cb..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import { Container } from 'react-bootstrap';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-
-export const Component = () => {
-       const { t } = useTranslation();
-
-       return <Container>
-               <h1>{t('twitchLegal.heading')}</h1>
-               <Helmet>
-                       <title>{t('twitchLegal.heading')}</title>
-               </Helmet>
-               <p>{t('twitchLegal.p1')}</p>
-               <p>{t('twitchLegal.p2')}</p>
-       </Container>;
-};
diff --git a/resources/js/pages/TwitchLegal.jsx b/resources/js/pages/TwitchLegal.jsx
new file mode 100644 (file)
index 0000000..197a5cb
--- /dev/null
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Container } from 'react-bootstrap';
+import { Helmet } from 'react-helmet';
+import { useTranslation } from 'react-i18next';
+
+export const Component = () => {
+       const { t } = useTranslation();
+
+       return <Container>
+               <h1>{t('twitchLegal.heading')}</h1>
+               <Helmet>
+                       <title>{t('twitchLegal.heading')}</title>
+               </Helmet>
+               <p>{t('twitchLegal.p1')}</p>
+               <p>{t('twitchLegal.p2')}</p>
+       </Container>;
+};
diff --git a/resources/js/pages/User.js b/resources/js/pages/User.js
deleted file mode 100644 (file)
index 9e8d22a..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-import axios from 'axios';
-import React, { useEffect, useState } from 'react';
-import { Helmet } from 'react-helmet';
-import { useParams } from 'react-router-dom';
-
-import NotFound from './NotFound';
-import CanonicalLinks from '../components/common/CanonicalLinks';
-import ErrorBoundary from '../components/common/ErrorBoundary';
-import ErrorMessage from '../components/common/ErrorMessage';
-import Loading from '../components/common/Loading';
-import Profile from '../components/users/Profile';
-
-const User = () => {
-       const params = useParams();
-       const { id } = params;
-
-       const [error, setError] = useState(null);
-       const [loading, setLoading] = useState(true);
-       const [user, setUser] = useState(null);
-
-       useEffect(() => {
-               setLoading(true);
-               const ctrl = new AbortController();
-               axios
-                       .get(`/api/users/${id}`, { signal: ctrl.signal })
-                       .then(response => {
-                               setError(null);
-                               setLoading(false);
-                               setUser(response.data);
-                       })
-                       .catch(error => {
-                               setError(error);
-                               setLoading(false);
-                               setUser(null);
-                       });
-               return () => {
-                       ctrl.abort();
-               };
-       }, [id]);
-
-       useEffect(() => {
-               const cb = (e) => {
-                       if (e.user) {
-                               setUser(user => e.user.id === user.id ? { ...user, ...e.user } : user);
-                       }
-               };
-               window.Echo.channel('App.Control')
-                       .listen('UserChanged', cb);
-               return () => {
-                       window.Echo.channel('App.Control')
-                               .stopListening('UserChanged', cb);
-               };
-       }, []);
-
-       if (loading) {
-               return <Loading />;
-       }
-
-       if (error) {
-               return <ErrorMessage error={error} />;
-       }
-
-       if (!user) {
-               return <NotFound />;
-       }
-
-       return <ErrorBoundary>
-               <Helmet>
-                       <title>{user.nickname || user.username}</title>
-               </Helmet>
-               <CanonicalLinks base={`/users/${user.id}`} />
-               <Profile user={user} />
-       </ErrorBoundary>;
-};
-
-export default User;
diff --git a/resources/js/pages/User.jsx b/resources/js/pages/User.jsx
new file mode 100644 (file)
index 0000000..58796c8
--- /dev/null
@@ -0,0 +1,86 @@
+import axios from 'axios';
+import React, { useEffect, useState } from 'react';
+import { Helmet } from 'react-helmet';
+import { useParams } from 'react-router-dom';
+
+import NotFound from './NotFound';
+import CanonicalLinks from '../components/common/CanonicalLinks';
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import ErrorMessage from '../components/common/ErrorMessage';
+import Loading from '../components/common/Loading';
+import Profile from '../components/users/Profile';
+
+const User = () => {
+       const params = useParams();
+       const { id } = params;
+
+       const [error, setError] = useState(null);
+       const [loading, setLoading] = useState(true);
+       const [user, setUser] = useState(null);
+
+       useEffect(() => {
+               setLoading(true);
+               const ctrl = new AbortController();
+               axios
+                       .get(`/api/users/${id}`, {
+                               params: {
+                                       with: [
+                                               'episodes_as_comms',
+                                               'episodes_as_runner',
+                                               'episodes_as_setup',
+                                               'episodes_as_tracker',
+                                       ],
+                               },
+                               signal: ctrl.signal,
+                       })
+                       .then(response => {
+                               setError(null);
+                               setLoading(false);
+                               setUser(response.data);
+                       })
+                       .catch(error => {
+                               setError(error);
+                               setLoading(false);
+                               setUser(null);
+                       });
+               return () => {
+                       ctrl.abort();
+               };
+       }, [id]);
+
+       useEffect(() => {
+               const cb = (e) => {
+                       if (e.user) {
+                               setUser(user => e.user.id === user.id ? { ...user, ...e.user } : user);
+                       }
+               };
+               window.Echo.channel('App.Control')
+                       .listen('UserChanged', cb);
+               return () => {
+                       window.Echo.channel('App.Control')
+                               .stopListening('UserChanged', cb);
+               };
+       }, []);
+
+       if (loading) {
+               return <Loading />;
+       }
+
+       if (error) {
+               return <ErrorMessage error={error} />;
+       }
+
+       if (!user) {
+               return <NotFound />;
+       }
+
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>{user.nickname || user.username}</title>
+               </Helmet>
+               <CanonicalLinks base={`/users/${user.id}`} />
+               <Profile user={user} />
+       </ErrorBoundary>;
+};
+
+export default User;
diff --git a/resources/js/pages/ZootrMixedPoolsTracker.jsx b/resources/js/pages/ZootrMixedPoolsTracker.jsx
new file mode 100644 (file)
index 0000000..100af98
--- /dev/null
@@ -0,0 +1,14 @@
+import React from 'react';
+import { Helmet } from 'react-helmet';
+
+import ErrorBoundary from '../components/common/ErrorBoundary';
+import Tracker from '../components/zootr/MixedPoolsTracker';
+
+export const Component = () => {
+       return <ErrorBoundary>
+               <Helmet>
+                       <title>ZOOTR Mixed Pools Tracker</title>
+               </Helmet>
+               <Tracker />
+       </ErrorBoundary>;
+};
diff --git a/resources/js/setup-jest.js b/resources/js/setup-jest.js
deleted file mode 100644 (file)
index 7b0828b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-import '@testing-library/jest-dom';
index f49b5e3fa8bf3a2124a339abaccf327a80f6bd39..db11306cad5d7f0a85361c393efbb8b17115b303 100644 (file)
@@ -25,5 +25,6 @@ $custom-colors: (
        "youtube": $youtube
 );
 
        "youtube": $youtube
 );
 
-// Form fixes
+// Fixes
 $form-select-indicator: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='#{$body-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/></svg>");
 $form-select-indicator: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='#{$body-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/></svg>");
+$table-color: $body-color;
index 7554a9e74dbc0769ca31f85bbb41bfc8fe83fee2..910838f82aaa17aad9e697123a8628407601c31a 100644 (file)
@@ -7,6 +7,7 @@
 // Custom
 @import 'common';
 @import 'channels';
 // Custom
 @import 'common';
 @import 'channels';
+@import 'chatlog';
 @import 'discord';
 @import 'doors';
 @import 'episodes';
 @import 'discord';
 @import 'doors';
 @import 'episodes';
@@ -21,3 +22,4 @@
 @import 'tournaments';
 @import 'tracker';
 @import 'users';
 @import 'tournaments';
 @import 'tracker';
 @import 'users';
+@import 'zootr';
index 7781b19e6e6e2f6ba7d32b7201bbfa4a4a41ae1e..abd87d068077d8ab49728a44712997e3f9b39a41 100644 (file)
@@ -1,18 +1,18 @@
-@import '~bootstrap/scss/functions';
+@import 'bootstrap/scss/functions';
 
 @import 'variables';
 
 
 @import 'variables';
 
-@import "~bootstrap/scss/variables";
-@import "~bootstrap/scss/variables-dark";
+@import 'bootstrap/scss/variables';
+@import 'bootstrap/scss/variables-dark';
 
 $theme-colors: map-merge($theme-colors, $custom-colors);
 
 
 $theme-colors: map-merge($theme-colors, $custom-colors);
 
-@import "~bootstrap/scss/maps";
-@import "~bootstrap/scss/mixins";
-@import "~bootstrap/scss/root";
+@import 'bootstrap/scss/maps';
+@import 'bootstrap/scss/mixins';
+@import 'bootstrap/scss/root';
 
 
-@import "~bootstrap/scss/utilities";
+@import 'bootstrap/scss/utilities';
 
 $utilities: map-merge($utilities, ("font-size": map-merge(map-get($utilities, "font-size"), (responsive: true))));
 
 
 $utilities: map-merge($utilities, ("font-size": map-merge(map-get($utilities, "font-size"), (responsive: true))));
 
-@import '~bootstrap/scss/bootstrap';
+@import 'bootstrap/scss/bootstrap';
index a72080525c36779e95271e42cea8fc2ff595263e..ba961800bfd916fc53c14d7259172764049d7851 100644 (file)
                background-color: $danger;
        }
 }
                background-color: $danger;
        }
 }
+
+.horstielog-channels {
+       position: relative;
+
+       .channel-list {
+               position: sticky;
+               top: 0;
+       }
+
+       .channel-item {
+               display: block;
+               margin: 1rem 0;
+               padding: 0.5ex 1ex;
+               background: rgba(0, 0, 0, 0.3);
+               border-radius: 0.5ex;
+               color: inherit;
+               text-decoration: none;
+
+               &:hover {
+                       .channel-title, .channel-viewers {
+                               color: $twitch;
+                       }
+               }
+
+               &.not-live {
+                       background: rgba(0, 0, 0, 0.1);
+               }
+       }
+}
diff --git a/resources/sass/chatlog.scss b/resources/sass/chatlog.scss
new file mode 100644 (file)
index 0000000..63f9a00
--- /dev/null
@@ -0,0 +1,4 @@
+.chat-log-list {
+       padding: 0.5ex 1ex;
+       background: $dark;
+}
index 1f73fb450a0c0ca07ba6390e6393f6ad7625b98f..f81daa321f202c6b8a2ad57de522272a2833b051 100644 (file)
@@ -30,6 +30,41 @@ h1 {
        }
 }
 
        }
 }
 
+@keyframes loading-pulse {
+       from {
+               box-shadow: 0 0 0 2em #aaa;
+       }
+       to {
+               box-shadow: 0 0 1em 4em #aaa;
+       }
+}
+
+.loading {
+       display: flex;
+       align-items: center;
+       justify-content: center;
+       height: 80vh;
+       .circle {
+               display: flex;
+               align-items: center;
+               justify-content: center;
+               content: "";
+               background: #888;
+               width: min(30vw, 30vh);
+               height: min(30vw, 30vh);
+               border-radius: min(15vw, 15vh);
+               line-height: min(15vw, 15vh);
+               animation-name: loading-pulse;
+               animation-duration: 2s;
+               animation-iteration-count: infinite;
+               animation-direction: alternate;
+       }
+       .text {
+               font-size: min(4vw, 4vh);
+               min-font-size: 200%;
+       }
+}
+
 .modal-90w {
        width: 90%;
        max-width: none !important;
 .modal-90w {
        width: 90%;
        max-width: none !important;
index 6caf0dd6eafc8cdbaf9e23f71b5ce91be3eeb3f5..02d2a70185b91f723612ef0f58010602e424ba2c 100644 (file)
@@ -8,6 +8,11 @@
        z-index: 1;
 }
 
        z-index: 1;
 }
 
+.episodes-list.compact .episodes-group-heading {
+       padding-bottom: 1rem;
+       background: linear-gradient(180deg, $body-bg, $body-bg 75%, transparent);
+}
+
 .episodes-item {
        background-size: 6rem auto;
        background-repeat: no-repeat;
 .episodes-item {
        background-size: 6rem auto;
        background-repeat: no-repeat;
index fc96e5d93b54dfa2c33ebcca4f75d8d6c5e12a50..1005c7241f9e58c673067b1202b90368b9e6b4ae 100644 (file)
@@ -1,13 +1,35 @@
+.front-page {
+       h1 {
+               margin-top: 2em;
+               margin-bottom: 2em;
+       }
+       h2 {
+               margin-top: 3em;
+               margin-bottom: 2em;
+       }
+}
 .front-panel {
        display: block;
 .front-panel {
        display: block;
+       color: inherit;
        font-size: 200%;
        font-weight: bold;
        font-size: 200%;
        font-weight: bold;
-       margin: 3em 0;
+       text-align: center;
+       text-decoration: none;
        width: 100%;
 
        .image {
                border-radius: 2em;
        width: 100%;
 
        .image {
                border-radius: 2em;
-               width: 100%;
+               width: 75%;
                height: auto;
        }
                height: auto;
        }
+       .title {
+       }
+
+       &:focus, &:hover, &:active {
+               text-decoration: underline;
+               .image {
+                       border: medium solid $light;
+                       box-shadow: 0 0 1em $light;
+               }
+       }
 }
 }
index f569bdcf57eeea2bda3d1adbac02b83a05632b65..b1ef0537bb8e746372b7dd6a8e2e280dedac6b67 100644 (file)
@@ -29,6 +29,9 @@
                                box-shadow: none;
                                top: 0.5ex;
                        }
                                box-shadow: none;
                                top: 0.5ex;
                        }
+                       &:focus {
+                               outline: medium dashed $light;
+                       }
 
                        .time {
                                min-width: 9ex;
 
                        .time {
                                min-width: 9ex;
index 907d6e946425c5fb9d1d12ad26e5f00d3901bd76..2ff6221d0d87e3461339ebab5dd2d76bec0ced90 100644 (file)
@@ -16,6 +16,8 @@
                }
 
                .info {
                }
 
                .info {
+                       display: flex;
+                       flex-direction: column;
                        padding-right: 1rem;
                        min-width: 13em;
 
                        padding-right: 1rem;
                        min-width: 13em;
 
                                }
                        }
 
                                }
                        }
 
+                       .bottom-half {
+                               margin-top: auto;
+                       }
+
                        .seed-code, .btn, .rolled-by {
                                margin-bottom: 1ex;
                        }
                        .seed-code, .btn, .rolled-by {
                                margin-bottom: 1ex;
                        }
diff --git a/resources/sass/zootr.scss b/resources/sass/zootr.scss
new file mode 100644 (file)
index 0000000..e83468d
--- /dev/null
@@ -0,0 +1,153 @@
+.mixed-pools-tracker {
+       padding: 1ex;
+       font-size: 80%;
+
+       .columns {
+               display: flex;
+               flex-wrap: wrap;
+               gap: 1em;
+       }
+       .column {
+               width: 20em;
+       }
+
+       .entrance-group {
+               margin: 1em 0;
+
+               h2 {
+                       position: relative;
+                       font-size: 110%;
+                       margin: 1ex 0;
+                       padding: .25ex;
+                       text-align: center;
+               }
+               .checks {
+                       position: absolute;
+                       top: .5ex;
+                       right: .5ex;
+                       font-weight: normal;
+                       font-size: 80%;
+               }
+       }
+       .entrance-row {
+               display: flex;
+               align-items: stretch;
+       }
+       .entrance-label {
+               margin: 0;
+               padding: 0 .25ex;
+               border: thin solid black;
+               width: 50%;
+       }
+       .entrance-select {
+               position: relative;
+               border: thin solid black;
+               width: 50%;
+       }
+       .entrance-search {
+               border: none;
+               background: #ddd;
+               width: 100%;
+       }
+       .entrance-value {
+               position: absolute;
+               top: 0;
+               right: 0;
+               bottom: 0;
+               left: 0;
+               padding: 0 .25ex;
+               cursor: pointer;
+               user-select: none;
+       }
+       .entrance-row.is-trash {
+               .entrance-label, .entrance-value {
+                       opacity: 0.05;
+               }
+               .entrance-select {
+                       border-color: rgba(0, 0, 0, 0.05);
+               }
+               .entrance-search {
+                       background: transparent;
+               }
+       }
+       .entrance-options {
+               display: none;
+               position: absolute;
+               top: 100%;
+               right: 0;
+               width: 15em;
+               box-shadow: 0 .25ex 1ex black;
+               max-height: 20em;
+               overflow-y: auto;
+       }
+       .entrance-select.is-open {
+               .entrance-value {
+                       opacity: .2;
+               }
+               .entrance-options {
+                       display: block;
+                       z-index: 1;
+               }
+       }
+       .entrance-option {
+               border: thin solid grey;
+               cursor: pointer;
+       }
+       .map {
+               svg {
+                       max-width: 104em;
+               }
+               .connector {
+                       stroke: #cc0000;
+                       &.is-via {
+                               stroke-dasharray: 3 3;
+                       }
+                       &.is-trash {
+                               stroke: #000000;
+                               opacity: 0.2;
+                       }
+                       &:hover {
+                               filter: drop-shadow(0 0 1px #000000) drop-shadow(0 0 2px #000000);
+                               opacity: 1;
+                               stroke-width: 3px;
+                       }
+               }
+               .annotation {
+                       pointer-events: none;
+               }
+               .area-label {
+                       pointer-events: none;
+                       font-size: 10px;
+                       font-weight: bold;
+                       stroke: #000000;
+                       stroke-width: 3px;
+                       paint-order: stroke fill;
+                       text-anchor: middle;
+                       alignment-baseline: middle;
+                       opacity: 0.25;
+               }
+               .area:hover .area-label {
+                       opacity: 1;
+               }
+               .entrance {
+                       &.is-trash {
+                               fill: #000000;
+                               opacity: 0.1;
+                       }
+                       &:hover, &:focus, &:active {
+                               opacity: 1;
+                               stroke: #ffffff;
+                               filter: drop-shadow(0 0 1px #000000) drop-shadow(0 0 2px #000000);
+                       }
+                       &.is-dragging {
+                               stroke: #cc0000;
+                               filter: drop-shadow(0 0 1px #cc0000) drop-shadow(0 0 2px #cc0000);
+                       }
+               }
+       }
+       .menu-bar {
+               max-width: 104em;
+               display: flex;
+               justify-content: space-between;
+       }
+}
index f1b807942ec01263ec21b8b33e570f67ded25271..a4b4a421023bc3bdca429d6ee6412b58193b19b6 100644 (file)
                <meta property="twitter:image" content="{{ $image }}">
 @endisset
 
                <meta property="twitter:image" content="{{ $image }}">
 @endisset
 
-               <script src="{{ mix('js/manifest.js') }}" defer></script>
-               <script src="{{ mix('js/vendor.js') }}" defer></script>
-               <script src="{{ mix('js/index.js') }}" defer></script>
-
-               <link href="{{ mix('css/app.css') }}" rel="stylesheet">
+               @viteReactRefresh
+               @vite(['resources/js/index.jsx'])
        </head>
        <body>
                <div id="react-root" class="title m-b-md">
        </head>
        <body>
                <div id="react-root" class="title m-b-md">
index 69a4bbfdc02f9159c52aeaa7bc0aca367011d944..94280659e50780b9e297a54cfa1f6bdf986cfc68 100644 (file)
@@ -39,10 +39,15 @@ Route::put('channels/{channel}/guessing-game/{name}', 'App\Http\Controllers\Chan
 
 Route::get('guessing-game-monitor/{key}', 'App\Http\Controllers\ChannelController@getGuessingGameMonitor');
 
 
 Route::get('guessing-game-monitor/{key}', 'App\Http\Controllers\ChannelController@getGuessingGameMonitor');
 
+Route::get('chatbotlogs', 'App\Http\Controllers\ChatBotLogController@search');
+Route::get('chatbotlogs/{entry}/context', 'App\Http\Controllers\ChatBotLogController@getContext');
+
 Route::get('content', 'App\Http\Controllers\TechniqueController@search');
 Route::get('content/{tech:name}', 'App\Http\Controllers\TechniqueController@single');
 Route::put('content/{content}', 'App\Http\Controllers\TechniqueController@update');
 
 Route::get('content', 'App\Http\Controllers\TechniqueController@search');
 Route::get('content/{tech:name}', 'App\Http\Controllers\TechniqueController@single');
 Route::put('content/{content}', 'App\Http\Controllers\TechniqueController@update');
 
+Route::post('discord-bot/{guild}/send-message', 'App\Http\Controllers\DiscordBotController@sendMessage');
+
 Route::get('discord-channels/{channel_id}', 'App\Http\Controllers\DiscordChannelController@single');
 
 Route::get('discord-guilds', 'App\Http\Controllers\DiscordGuildController@search');
 Route::get('discord-channels/{channel_id}', 'App\Http\Controllers\DiscordChannelController@single');
 
 Route::get('discord-guilds', 'App\Http\Controllers\DiscordGuildController@search');
@@ -65,11 +70,13 @@ Route::get('pages/{type}', 'App\Http\Controllers\TechniqueController@byType');
 Route::get('pages/{type}/{name}', 'App\Http\Controllers\TechniqueController@byTypeAndName');
 
 Route::get('protocol/{tournament}', 'App\Http\Controllers\ProtocolController@forTournament');
 Route::get('pages/{type}/{name}', 'App\Http\Controllers\TechniqueController@byTypeAndName');
 
 Route::get('protocol/{tournament}', 'App\Http\Controllers\ProtocolController@forTournament');
+Route::get('protocol/{tournament}/{round}', 'App\Http\Controllers\ProtocolController@forRound');
 
 Route::post('results', 'App\Http\Controllers\ResultController@create');
 
 Route::post('rounds', 'App\Http\Controllers\RoundController@create');
 Route::put('rounds/{round}', 'App\Http\Controllers\RoundController@update');
 
 Route::post('results', 'App\Http\Controllers\ResultController@create');
 
 Route::post('rounds', 'App\Http\Controllers\RoundController@create');
 Route::put('rounds/{round}', 'App\Http\Controllers\RoundController@update');
+Route::delete('rounds/{round}', 'App\Http\Controllers\RoundController@delete');
 Route::post('rounds/{round}/lock', 'App\Http\Controllers\RoundController@lock');
 Route::post('rounds/{round}/setSeed', 'App\Http\Controllers\RoundController@setSeed');
 Route::post('rounds/{round}/unlock', 'App\Http\Controllers\RoundController@unlock');
 Route::post('rounds/{round}/lock', 'App\Http\Controllers\RoundController@lock');
 Route::post('rounds/{round}/setSeed', 'App\Http\Controllers\RoundController@setSeed');
 Route::post('rounds/{round}/unlock', 'App\Http\Controllers\RoundController@unlock');
index 53597afa3bc10144504e95a0c972bde7c3ab409a..2dcf2980f5a5cde028d0eaeb78d3145a700e4aee 100644 (file)
@@ -1,11 +1,11 @@
 <?php
 
 <?php
 
-use App\Http\Controllers\DiscordController;
 use App\Http\Controllers\SitemapXmlController;
 use App\Http\Controllers\TechniqueController;
 use App\Models\Event;
 use App\Models\Technique;
 use Illuminate\Support\Facades\Route;
 use App\Http\Controllers\SitemapXmlController;
 use App\Http\Controllers\TechniqueController;
 use App\Models\Event;
 use App\Models\Technique;
 use Illuminate\Support\Facades\Route;
+use Jakyeru\Larascord\Http\Controllers\DiscordController;
 
 /*
 |--------------------------------------------------------------------------
 
 /*
 |--------------------------------------------------------------------------
@@ -43,11 +43,3 @@ Route::get('/tech/{name}', function($name) {
 Route::get('/twitch/guessing-game-leaderboard/{channel:twitch_id}/{type}', 'App\Http\Controllers\ChannelController@getGuessingGameLeaderboard');
 
 Route::view('/{path?}', 'app')->where('path', '.*');
 Route::get('/twitch/guessing-game-leaderboard/{channel:twitch_id}/{type}', 'App\Http\Controllers\ChannelController@getGuessingGameLeaderboard');
 
 Route::view('/{path?}', 'app')->where('path', '.*');
-
-Route::group(['prefix' => config('larascord.prefix'), 'middleware' => ['web']], function() {
-       Route::get('/callback', [DiscordController::class, 'handle'])
-               ->name('larascord.login');
-
-       Route::redirect('/refresh-token', '/login')
-               ->name('larascord.refresh_token');
-});
index e5166b2f3c0618a19f0146c3831ccaa73d93e10d..c1b24f9d7cc66ee664a0edaa4cbec16219d89fc4 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
 <?php
 
-namespace Tests\Unit\Models;
+namespace Tests\Unit\TwitchBot;
 
 use App\TwitchBot\IRCMessage;
 use PHPUnit\Framework\TestCase;
 
 use App\TwitchBot\IRCMessage;
 use PHPUnit\Framework\TestCase;
@@ -17,16 +17,16 @@ class IRCMessageTest extends TestCase {
                        'display-name' => 'Magnohato',
                        'emotes' => 'emotesv2_fb9cdf0d7fae484ab2e1d20e59a17ed2:0-11,19-30,38-49,58-69,80-91,100-111,122-133,139-150',
                        'first-msg' => '0',
                        'display-name' => 'Magnohato',
                        'emotes' => 'emotesv2_fb9cdf0d7fae484ab2e1d20e59a17ed2:0-11,19-30,38-49,58-69,80-91,100-111,122-133,139-150',
                        'first-msg' => '0',
-                       'flags' => '',
+                       'flags' => null,
                        'id' => '4b6fc216-18de-41d0-b92d-aeb28c690788',
                        'mod' => '0',
                        'id' => '4b6fc216-18de-41d0-b92d-aeb28c690788',
                        'mod' => '0',
-                       'returning-chattea' => '0',
+                       'returning-chatter' => '0',
                        'room-id' => '30178469',
                        'subscriber' => '1',
                        'tmi-sent-ts' => '1712602818970',
                        'turbo' => '0',
                        'user-id' => '58325205',
                        'room-id' => '30178469',
                        'subscriber' => '1',
                        'tmi-sent-ts' => '1712602818970',
                        'turbo' => '0',
                        'user-id' => '58325205',
-                       'user-type' => '',
+                       'user-type' => null,
                ], $msg->tags);
                $this->assertEquals('PRIVMSG', $msg->command);
                $this->assertEquals('magnohato', $msg->nick);
                ], $msg->tags);
                $this->assertEquals('PRIVMSG', $msg->command);
                $this->assertEquals('magnohato', $msg->nick);
index 832b9702cf2a345b82023f022bc592d4b157cdaa..3678dccc1fa6f8e20d284e09ba4904406818a5ca 100644 (file)
@@ -88,10 +88,16 @@ class TokenizedMessageTest extends TestCase {
                $this->assertTrue(TokenizedMessage::fromString('hello would you like some followers?')->isSpammy());
                $this->assertTrue(TokenizedMessage::fromString('get view ers for free')->isSpammy());
 
                $this->assertTrue(TokenizedMessage::fromString('hello would you like some followers?')->isSpammy());
                $this->assertTrue(TokenizedMessage::fromString('get view ers for free')->isSpammy());
 
+               $this->assertTrue(TokenizedMessage::fromString('yayklaygaming verschwindet für \'ne Weile in den Lurk. Cool, dass Du vorbeigeschaut hast xallggCheers PogChamp')->isSpammy());
+               $this->assertTrue(TokenizedMessage::fromString('XallGG is now live! Streaming The Legend of Zelda: A Link to the Past: Casual Boots Seed zum Spaß/Practice')->isSpammy());
                $this->assertTrue(TokenizedMessage::fromString('also bitte, horstie')->isSpammy());
 
                $this->assertTrue(TokenizedMessage::fromString('hey maengi, vielen dank für den raid')->isSpammy());
                $this->assertTrue(TokenizedMessage::fromString('Willkommen auf Starbase 47')->isSpammy());
        }
 
                $this->assertTrue(TokenizedMessage::fromString('also bitte, horstie')->isSpammy());
 
                $this->assertTrue(TokenizedMessage::fromString('hey maengi, vielen dank für den raid')->isSpammy());
                $this->assertTrue(TokenizedMessage::fromString('Willkommen auf Starbase 47')->isSpammy());
        }
 
+       public function test_tokenizer() {
+               $this->assertTrue(TokenizedMessage::fromString('@HorstieBot wie viele warps?')->hasConsecutiveTokens(['wie', 'viele']));
+               $this->assertFalse(TokenizedMessage::fromString('@HorstieBot wie viele warps?')->hasConsecutiveTokens(['wo', 'wurst']));
+       }
 }
 }
index 2d86f3f8330672dfe2715c602e890d0c9afeec0b..eecff377417b09730f9bba25cd23a058721e37f6 100644 (file)
@@ -1,6 +1,8 @@
+import { describe, expect, test } from 'vitest';
+
 import {
        parseTime,
 import {
        parseTime,
-} from 'helpers/Result';
+} from '@/helpers/Result';
 
 describe('parseTime', () => {
        test('null on empty', () => {
 
 describe('parseTime', () => {
        test('null on empty', () => {
index 86233f8916f846ee4262f3213ccfcae24982fd02..7a7b6e24f13663d867b6239f7e2dd397dcca1b75 100644 (file)
@@ -1,6 +1,8 @@
+import { describe, expect, test } from 'vitest';
+
 import {
        getUserName,
 import {
        getUserName,
-} from 'helpers/User';
+} from '@/helpers/User';
 
 describe('getUserName', () => {
        test('empty on missing user', () => {
 
 describe('getUserName', () => {
        test('empty on missing user', () => {
index 5bb9ca3fd841a38f4b05c6bff543c84fc6ea3813..f072f49c7145cc7a70e4e0c18f53e03232b12454 100644 (file)
@@ -1,10 +1,12 @@
+import { describe, expect, test } from 'vitest';
+
 import {
        CONFIG,
        applyLogic,
        configureDungeons,
        getLocationStatus,
        makeEmptyState,
 import {
        CONFIG,
        applyLogic,
        configureDungeons,
        getLocationStatus,
        makeEmptyState,
-} from 'helpers/tracker';
+} from '@/helpers/tracker';
 
 describe('base reachability', () => {
        const config = {
 
 describe('base reachability', () => {
        const config = {
index 615c385af393df5731d4d4d2cbab3e7b10ae8a0d..7b675e3e19a706e3383c6cebf59453db5a3e3449 100644 (file)
@@ -1,10 +1,12 @@
+import { describe, expect, test } from 'vitest';
+
 import {
        CONFIG,
        applyLogic,
        configureDungeons,
        getLocationStatus,
        makeEmptyState,
 import {
        CONFIG,
        applyLogic,
        configureDungeons,
        getLocationStatus,
        makeEmptyState,
-} from 'helpers/tracker';
+} from '@/helpers/tracker';
 
 describe('base reachability', () => {
        const config = { ...CONFIG };
 
 describe('base reachability', () => {
        const config = { ...CONFIG };
index ceaaaccd254fc3dbb354fae469d8d76d2c3e8001..ed3372c2c126fa0a684d9982a3ecb69760f1f030 100644 (file)
@@ -1,10 +1,12 @@
+import { describe, expect, test } from 'vitest';
+
 import {
        CONFIG,
        configureDungeons,
        getDungeonBoss,
        getDungeonRemainingItems,
        makeEmptyState,
 import {
        CONFIG,
        configureDungeons,
        getDungeonBoss,
        getDungeonRemainingItems,
        makeEmptyState,
-} from 'helpers/tracker';
+} from '@/helpers/tracker';
 
 describe('default dungeon configuration', () => {
        const dungeons = configureDungeons(CONFIG);
 
 describe('default dungeon configuration', () => {
        const dungeons = configureDungeons(CONFIG);
diff --git a/vite.config.js b/vite.config.js
new file mode 100644 (file)
index 0000000..f036e30
--- /dev/null
@@ -0,0 +1,17 @@
+import { defineConfig } from 'vite';
+import laravel from 'laravel-vite-plugin';
+import react from '@vitejs/plugin-react';
+import { manualChunksPlugin } from 'vite-plugin-webpackchunkname';
+
+export default defineConfig({
+    plugins: [
+        laravel([
+            'resources/js/index.jsx',
+        ]),
+        react(),
+               manualChunksPlugin(),
+    ],
+       test: {
+               environment: 'jsdom',
+       },
+});
diff --git a/webpack.mix.js b/webpack.mix.js
deleted file mode 100644 (file)
index 60085ab..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-const mix = require('laravel-mix');
-
-/*
- |--------------------------------------------------------------------------
- | Mix Asset Management
- |--------------------------------------------------------------------------
- |
- | Mix provides a clean, fluent API for defining some Webpack build steps
- | for your Laravel application. By default, we are compiling the Sass
- | file for the application as well as bundling up all the JS files.
- |
- */
-
-mix.js('resources/js/index.js', 'public/js')
-       .react()
-       .sass('resources/sass/app.scss', 'public/css')
-       .extract([
-               '@babel/runtime',
-               '@fortawesome/fontawesome-free',
-               '@fortawesome/fontawesome-svg-core',
-               '@fortawesome/free-brands-svg-icons',
-               '@fortawesome/free-solid-svg-icons',
-               '@fortawesome/react-fontawesome',
-               '@popperjs/core',
-               '@restart/hooks',
-               '@restart/ui',
-               'axios',
-               'bootstrap',
-               'call-bind',
-               'classnames',
-               'formik',
-               'history',
-               'i18next',
-               'i18next-browser-languagedetector',
-               'invariant',
-               'laravel-echo',
-               'lodash',
-               'lodash-es',
-               'moment',
-               'numeral',
-               'property-expr',
-               'pusher-js',
-               'qs',
-               'react',
-               'react-bootstrap',
-               'react-dom',
-               'react-fast-compare',
-               'react-i18next',
-               'react-is',
-               'react-lifecycles-compat',
-               'react-resize-detector',
-               'react-router',
-               'react-router-bootstrap',
-               'react-router-dom',
-               'react-smooth',
-               'react-transition-group',
-               'reduce-css-calc',
-               'regenerator-runtime',
-               'resize-observer-polyfill',
-               'scheduler',
-               'side-channel',
-               'tiny-warning',
-               'toastr',
-               'toposort',
-               'uncontrollable',
-               'void-elements',
-               'warning',
-               'yup',
-       ])
-       .sourceMaps(true)
-       .version();
-//if (mix.inProduction()) {
-       mix.webpackConfig({
-               output: {
-                       chunkFilename: 'js/chunks/[name].[chunkhash].js',
-               },
-       });
-//} else {
-//     mix.webpackConfig({
-//             output: {
-//                     asyncChunks: false,
-//             },
-//     });
-//}