From 1155024c9ee560fbb67b5e12620cae45da6c6421 Mon Sep 17 00:00:00 2001 From: BestGamersH Date: Wed, 12 Apr 2023 17:16:43 +0530 Subject: [PATCH] Main --- .dockerignore | 2 + .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/bug_report.md | 36 ++ .github/ISSUE_TEMPLATE/config.yml | 5 + .github/ISSUE_TEMPLATE/feature_request.md | 25 + .github/PULL_REQUEST_TEMPLATE.md | 18 + .github/SUPPORT.md | 9 + .github/stale.yml | 11 + .gitignore | 125 ++++ .replit | 6 + CODE_OF_CONDUCT.md | 76 +++ CONTRIBUTING.md | 93 +++ Dockerfile | 6 + LICENSE.md | 8 + Procfile | 1 + README.md | 47 ++ api/index.js | 105 +++ api/middlewares/auth.js | 16 + api/router.js | 48 ++ api/routes/dashboard.js | 17 + api/routes/data.js | 26 + app.json | 39 ++ assets/logo.gif | Bin 0 -> 52397 bytes commands/context/play.js | 191 ++++++ commands/slash/247.js | 79 +++ commands/slash/autoleave.js | 62 ++ commands/slash/autopause.js | 62 ++ commands/slash/autoqueue.js | 65 ++ commands/slash/clean.js | 49 ++ commands/slash/clear.js | 54 ++ commands/slash/filters.js | 102 +++ commands/slash/guildleave.js | 56 ++ commands/slash/help.js | 135 ++++ commands/slash/invite.js | 30 + commands/slash/loop.js | 51 ++ commands/slash/loopq.js | 53 ++ commands/slash/lyrics.js | 233 +++++++ commands/slash/move.js | 75 +++ commands/slash/nowplaying.js | 83 +++ commands/slash/pause.js | 58 ++ commands/slash/ping.js | 69 ++ commands/slash/play.js | 196 ++++++ commands/slash/previous.js | 67 ++ commands/slash/queue.js | 347 ++++++++++ commands/slash/reload.js | 89 +++ commands/slash/remove.js | 68 ++ commands/slash/replay.js | 51 ++ commands/slash/resume.js | 57 ++ commands/slash/save.js | 81 +++ commands/slash/search.js | 190 ++++++ commands/slash/seek.js | 82 +++ commands/slash/shuffle.js | 59 ++ commands/slash/skip.js | 59 ++ commands/slash/skipto.js | 81 +++ commands/slash/stats.js | 89 +++ commands/slash/stop.js | 55 ++ commands/slash/summon.js | 36 ++ commands/slash/volume.js | 68 ++ config.js | 48 ++ dashboard/.eslintrc.json | 3 + dashboard/.gitignore | 31 + dashboard/README.md | 41 ++ dashboard/components/StatCard.tsx | 20 + dashboard/components/content.tsx | 17 + dashboard/components/navbar.tsx | 31 + dashboard/components/server.tsx | 32 + dashboard/next-env.d.ts | 5 + dashboard/next.config.js | 6 + dashboard/out/404.html | 12 + .../static/chunks/123-d3ffcfb4730480c6.js | 1 + .../static/chunks/732-e52c1d2253f458fa.js | 1 + .../chunks/framework-4556c45dd113b893.js | 1 + .../static/chunks/main-a19d41ac16dbce80.js | 1 + .../chunks/pages/_app-79511e227f7b8d22.js | 1 + .../chunks/pages/_error-a4ba2246ff8fb532.js | 1 + .../pages/dashboard-8fe77e1aeec6ff87.js | 1 + .../chunks/pages/index-0494ad302e38da35.js | 1 + .../chunks/pages/login-8481030b110c33c9.js | 1 + .../chunks/pages/logout-7167c9506bd9bdd3.js | 1 + .../chunks/pages/servers-b957468847859725.js | 1 + .../pages/servers/[id]-9f8c48f5bf25bd78.js | 1 + .../chunks/polyfills-c67a75d1b6f99dc8.js | 1 + .../static/chunks/webpack-fd1bc4a65a80e5c8.js | 1 + .../wV3SzfWusZ8UapJ--_pvH/_buildManifest.js | 1 + .../wV3SzfWusZ8UapJ--_pvH/_ssgManifest.js | 1 + dashboard/out/dashboard.html | 1 + dashboard/out/index.html | 1 + dashboard/out/login.html | 1 + dashboard/out/logout.html | 1 + dashboard/out/servers.html | 1 + dashboard/out/servers/[id].html | 1 + dashboard/package.json | 29 + dashboard/pages/_app.tsx | 13 + dashboard/pages/_document.tsx | 32 + dashboard/pages/dashboard.tsx | 41 ++ dashboard/pages/index.tsx | 139 ++++ dashboard/pages/login.tsx | 18 + dashboard/pages/logout.tsx | 15 + dashboard/pages/servers.tsx | 25 + dashboard/pages/servers/[id].tsx | 29 + dashboard/svgs/AudiotrackRounded.svg | 5 + dashboard/svgs/DnsRounded.svg | 5 + dashboard/svgs/PersonRounded.svg | 5 + dashboard/svgs/RocketLaunchRounded.svg | 5 + dashboard/tsconfig.json | 30 + dashboard/utils/dashboard.ts | 17 + dashboard/utils/data.ts | 22 + deploy/destroy.js | 40 ++ deploy/global.js | 20 + deploy/guild.js | 32 + docker-compose.yml | 27 + docker/application.yml | 58 ++ events/interactionCreate.js | 78 +++ events/messageCreate.js | 41 ++ events/messageDelete.js | 13 + events/raw.js | 8 + events/ready.js | 9 + events/voiceStateUpdate.js | 215 +++++++ index.js | 27 + kickstartReplit.sh | 16 + lib/DiscordMusicBot.js | 600 ++++++++++++++++++ lib/EpicPlayer.d.ts | 17 + lib/EpicPlayer.js | 56 ++ lib/Logger.js | 51 ++ lib/SlashCommand.js | 25 + package.json | 81 +++ renovate.json | 5 + replit.nix | 6 + util/Controller.js | 156 +++++ util/db.js | 253 ++++++++ util/getChannel.js | 46 ++ util/getConfig.js | 17 + util/getLavalink.js | 16 + util/guildDb.js | 107 ++++ util/loadCommands.js | 44 ++ 135 files changed, 6664 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/CODEOWNERS create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/SUPPORT.md create mode 100644 .github/stale.yml create mode 100644 .gitignore create mode 100644 .replit create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 Dockerfile create mode 100644 LICENSE.md create mode 100644 Procfile create mode 100644 README.md create mode 100644 api/index.js create mode 100644 api/middlewares/auth.js create mode 100644 api/router.js create mode 100644 api/routes/dashboard.js create mode 100644 api/routes/data.js create mode 100644 app.json create mode 100644 assets/logo.gif create mode 100644 commands/context/play.js create mode 100644 commands/slash/247.js create mode 100644 commands/slash/autoleave.js create mode 100644 commands/slash/autopause.js create mode 100644 commands/slash/autoqueue.js create mode 100644 commands/slash/clean.js create mode 100644 commands/slash/clear.js create mode 100644 commands/slash/filters.js create mode 100644 commands/slash/guildleave.js create mode 100644 commands/slash/help.js create mode 100644 commands/slash/invite.js create mode 100644 commands/slash/loop.js create mode 100644 commands/slash/loopq.js create mode 100644 commands/slash/lyrics.js create mode 100644 commands/slash/move.js create mode 100644 commands/slash/nowplaying.js create mode 100644 commands/slash/pause.js create mode 100644 commands/slash/ping.js create mode 100644 commands/slash/play.js create mode 100644 commands/slash/previous.js create mode 100644 commands/slash/queue.js create mode 100644 commands/slash/reload.js create mode 100644 commands/slash/remove.js create mode 100644 commands/slash/replay.js create mode 100644 commands/slash/resume.js create mode 100644 commands/slash/save.js create mode 100644 commands/slash/search.js create mode 100644 commands/slash/seek.js create mode 100644 commands/slash/shuffle.js create mode 100644 commands/slash/skip.js create mode 100644 commands/slash/skipto.js create mode 100644 commands/slash/stats.js create mode 100644 commands/slash/stop.js create mode 100644 commands/slash/summon.js create mode 100644 commands/slash/volume.js create mode 100644 config.js create mode 100644 dashboard/.eslintrc.json create mode 100644 dashboard/.gitignore create mode 100644 dashboard/README.md create mode 100644 dashboard/components/StatCard.tsx create mode 100644 dashboard/components/content.tsx create mode 100644 dashboard/components/navbar.tsx create mode 100644 dashboard/components/server.tsx create mode 100644 dashboard/next-env.d.ts create mode 100644 dashboard/next.config.js create mode 100644 dashboard/out/404.html create mode 100644 dashboard/out/_next/static/chunks/123-d3ffcfb4730480c6.js create mode 100644 dashboard/out/_next/static/chunks/732-e52c1d2253f458fa.js create mode 100644 dashboard/out/_next/static/chunks/framework-4556c45dd113b893.js create mode 100644 dashboard/out/_next/static/chunks/main-a19d41ac16dbce80.js create mode 100644 dashboard/out/_next/static/chunks/pages/_app-79511e227f7b8d22.js create mode 100644 dashboard/out/_next/static/chunks/pages/_error-a4ba2246ff8fb532.js create mode 100644 dashboard/out/_next/static/chunks/pages/dashboard-8fe77e1aeec6ff87.js create mode 100644 dashboard/out/_next/static/chunks/pages/index-0494ad302e38da35.js create mode 100644 dashboard/out/_next/static/chunks/pages/login-8481030b110c33c9.js create mode 100644 dashboard/out/_next/static/chunks/pages/logout-7167c9506bd9bdd3.js create mode 100644 dashboard/out/_next/static/chunks/pages/servers-b957468847859725.js create mode 100644 dashboard/out/_next/static/chunks/pages/servers/[id]-9f8c48f5bf25bd78.js create mode 100644 dashboard/out/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js create mode 100644 dashboard/out/_next/static/chunks/webpack-fd1bc4a65a80e5c8.js create mode 100644 dashboard/out/_next/static/wV3SzfWusZ8UapJ--_pvH/_buildManifest.js create mode 100644 dashboard/out/_next/static/wV3SzfWusZ8UapJ--_pvH/_ssgManifest.js create mode 100644 dashboard/out/dashboard.html create mode 100644 dashboard/out/index.html create mode 100644 dashboard/out/login.html create mode 100644 dashboard/out/logout.html create mode 100644 dashboard/out/servers.html create mode 100644 dashboard/out/servers/[id].html create mode 100644 dashboard/package.json create mode 100644 dashboard/pages/_app.tsx create mode 100644 dashboard/pages/_document.tsx create mode 100644 dashboard/pages/dashboard.tsx create mode 100644 dashboard/pages/index.tsx create mode 100644 dashboard/pages/login.tsx create mode 100644 dashboard/pages/logout.tsx create mode 100644 dashboard/pages/servers.tsx create mode 100644 dashboard/pages/servers/[id].tsx create mode 100644 dashboard/svgs/AudiotrackRounded.svg create mode 100644 dashboard/svgs/DnsRounded.svg create mode 100644 dashboard/svgs/PersonRounded.svg create mode 100644 dashboard/svgs/RocketLaunchRounded.svg create mode 100644 dashboard/tsconfig.json create mode 100644 dashboard/utils/dashboard.ts create mode 100644 dashboard/utils/data.ts create mode 100644 deploy/destroy.js create mode 100644 deploy/global.js create mode 100644 deploy/guild.js create mode 100644 docker-compose.yml create mode 100644 docker/application.yml create mode 100644 events/interactionCreate.js create mode 100644 events/messageCreate.js create mode 100644 events/messageDelete.js create mode 100644 events/raw.js create mode 100644 events/ready.js create mode 100644 events/voiceStateUpdate.js create mode 100644 index.js create mode 100644 kickstartReplit.sh create mode 100644 lib/DiscordMusicBot.js create mode 100644 lib/EpicPlayer.d.ts create mode 100644 lib/EpicPlayer.js create mode 100644 lib/Logger.js create mode 100644 lib/SlashCommand.js create mode 100644 package.json create mode 100644 renovate.json create mode 100644 replit.nix create mode 100644 util/Controller.js create mode 100644 util/db.js create mode 100644 util/getChannel.js create mode 100644 util/getConfig.js create mode 100644 util/getLavalink.js create mode 100644 util/guildDb.js create mode 100644 util/loadCommands.js diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5171c54 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +node_modules +npm-debug.log \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..37f2229 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @SudhanPlayz @DarrenOfficial \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..41180bc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,36 @@ +--- +name: Bug report +about: Report incorrect or unexpected behavior of the Music Bot +title: "" +labels: "s: unverified, type: bug" +assignees: "" +--- + + + +## Please describe the problem you are having in as much detail as possible: + +## Include a reproducible code sample here, if possible: + +```js +// Place your code here +``` + +## Further details: + +- discord.js version: +- Node.js version: +- Operating system: +- Priority this issue should have – please be realistic and elaborate if possible: + +## Relevant client options: + +- partials: none +- gateway intents: none +- other: none + + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..63f6a8a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Discord server + url: https://discord.gg/sbySMS7m3v + about: Please visit our Discord server for questions and support requests. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..f236aa0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,25 @@ +--- +name: Feature request +about: Request a feature for the Music Bot +title: "" +labels: "type: enhancement" +assignees: "" +--- + + + +## Is your feature request related to a problem? Please describe. + +A clear and concise description of what the problem is. Eg. I'm always frustrated when [...] + +## Describe the ideal solution + +A clear and concise description of what you want to happen. + +## Describe alternatives you've considered + +A clear and concise description of any alternative solutions or features you've considered. + +## Additional context + +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..b32b9b3 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +## Please describe the changes this PR makes and why it should be merged: + +## Status and versioning classification: + + + +# Important. + +- Write in camelCase, not snake_case. +- Do not push to master/main without testing your changes first, make a branch + if you have to. \ No newline at end of file diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 0000000..65df635 --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,9 @@ +# Seeking support? + +We only use this issue tracker for bug reports and feature request. We are not able to provide general support or answer +questions in the form of GitHub issues. + +For general questions about the Music Bot and use please use the dedicated support channels in our Discord +server: https://discord.gg/sbySMS7m3v + +Any issues that don't directly involve a bug or a feature request will likely be closed and redirected. diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..8543ddc --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,11 @@ +# Configuration for probot-stale - https://github.com/probot/stale +daysUntilStale: 60 + +daysUntilClose: 5 +exemptLabels: + - Soon + +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a155dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,125 @@ +# Actual ignored paths for this repo +db.json +dbList.json +.guild_dbs/ +dev-config.js + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn +.yarn-integrity +yarn.lock + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and *not* Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Lockfiles +package-lock.json +yarn.lock + +# Volta +.pnp.cjs +.pnp.loader.mjs + +# IDE +.idea/ +.vscode/ +.history/ diff --git a/.replit b/.replit new file mode 100644 index 0000000..a3e78b2 --- /dev/null +++ b/.replit @@ -0,0 +1,6 @@ +run = "node index.js" +language = "Bash" + +[nix] +channel = "stable-22_05" + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..7fc268f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at SudhanPlayz@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b67848c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,93 @@ +

Contributing

+ +When contributing to this repository, please first discuss the change you wish to make via issue, +email, or any other method with the owners of this repository before making a change. + +Please note we have a code of conduct, please follow it in all your interactions with the project. + +## Pull Request Process + +1. Ensure any install or build dependencies are removed before the end of the layer when doing a + build. +2. Update the README.md with details of changes to the interface, this includes new environment + variables, exposed ports, useful file locations and container parameters. +3. Increase the version numbers in any examples files and the README.md to the new version that this + Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). +4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you + do not have permission to do that, you may request the second reviewer to merge it for you. + +## Code of Conduct + +### Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +### Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +### Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +### Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +### Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at SudhanPlayz@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +### Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org + +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..02d3b39 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,6 @@ +FROM node:17.9.1-alpine +WORKDIR /usr/src/app +COPY . . +RUN npm install +RUN npm run deploy +CMD [ "node", "index.js" ] diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..b273948 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,8 @@ +# License for Discord-MusicBot + +- The credits should not be changed. +- The bot-code should be used for **private hosting** and **personal usage** only. +- Using the code for public usage is **not allowed**. + +> **Note:** if you are found to be violating any of the above stated rule you might be asked to takedown your bot, happy +> listening!! Incase of any doubts in the license contact owner. \ No newline at end of file diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..9ebe8e8 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +worker: npm start diff --git a/README.md b/README.md new file mode 100644 index 0000000..34fdf6d --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +

Discord Music Bot

+ +## 🚧 | Prerequisites + +- [Node.js 16+](https://nodejs.org/en/download/) +- [Lavalink Server](https://code.darrennathanael.com/how-to-lavalink) +- You'll need to run `npm run deploy` or `yarn deploy`. to initialized the slash commands. _You can do this on your pc + locally_ + +> NOTE: Lavalink is needed for music functionality. You need to have a working Lavalink server to make the bot work. + +## 📝 | Important Note if you're Switching from v4 to v5 + +1. Download and configure v5 in a seperate folder. +2. Kick your bot out of your server. +3. Reinvite the Bot with the right + scopes. [Example Invite URL (Change CLIENT_ID)](https://discord.com/oauth2/authorize?client_id=CLIENT_ID&permissions=277083450689&scope=bot%20applications.commands) +4. Run `npm run deploy` or `yarn deploy` to initialize the slash commands. _You can do this on your pc locally_ + +## 📝 | Tutorial + +Soon + +## 📝 | [Support Server](https://discord.gg/jEZtK54m7n) + +If you have major coding issues with this bot, please join and ask for help. + +## 📸 | Screenshots + +Soon + +## 🚀 | Deploy + +[![Deploy to heroku](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/BestGamersH/Music-bot) +[![Open in Gitpod](https://camo.githubusercontent.com/76e60919474807718793857d8eb615e7a50b18b04050577e5a35c19421f260a3/68747470733a2f2f676974706f642e696f2f627574746f6e2f6f70656e2d696e2d676974706f642e737667)](https://gitpod.io/#https://github.com/BestGamersH/Music-bot) +[![Run on Repl.it](https://repl.it/badge/github/BestGamersH/Music-bot)](https://repl.it/github/BestGamersH/Music-bot) + + + +## 🌟 | Made with + +- [Discord.js](https://discord.js.org/) +- [Lavalink](https://github.com/freyacodes/Lavalink) with erela.js +- [Express](https://expressjs.com/) +- [Next JS](https://nextjs.org/) +- [Next UI](https://nextui.org) +- [Material UI Icons](https://mui.com/material-ui/material-icons/) diff --git a/api/index.js b/api/index.js new file mode 100644 index 0000000..4cb130a --- /dev/null +++ b/api/index.js @@ -0,0 +1,105 @@ +const express = require("express"); +const fs = require("fs"); +const { EventEmitter } = require("events"); +const { join } = require("path"); +const session = require("express-session"); +const DiscordStrategy = require("passport-discord").Strategy; +const passport = require("passport"); +const getConfig = require("../util/getConfig"); +const DiscordMusicBot = require("../lib/DiscordMusicBot"); +const router = require("./router"); + +passport.serializeUser(function (user, done) { + done(null, user); +}); + +passport.deserializeUser(function (obj, done) { + done(null, obj); +}); + +class Server extends EventEmitter { + /** + * Create server ;-; + * @param {DiscordMusicBot} client + */ + constructor(client) { + super(); + this.client = client; + getConfig().then(this.init.bind(this)); + } + + init(conf) { + this.config = conf; + this.app = express(); + + this.app.use(express.static(join(__dirname, "..", "public"))); + + // Static Routes for scripts + const dist = join(__dirname, "..", "dashboard", "out", "_next") + + this.app.use("/_next", express.static(dist)); + + // Session and Passport + this.app.use(session({ + resave: false, + saveUninitialized: false, + secret: this.config.cookieSecret, + cookie: { + secure: this.config.website.startsWith("https://"), + sameSite: true, + }, + })); + + this.initPassport(); + + this.app.use(router); + + //API + fs.readdir(join(__dirname, "routes"), (err, files) => { + if (err) { + return console.log(err); + } + files.forEach((file) => { + this.app.use( + "/api/" + file.split(".")[0], + require(join(__dirname, "routes") + "/" + file), + ); + }); + }); + + this.listen(); + } + + initPassport() { + this.app.use(passport.initialize()); + + const strategy = new DiscordStrategy( + { + clientID: this.config.clientId, + clientSecret: this.config.clientSecret, + callbackURL: this.config.website + "/api/callback", + scope: this.config.scopes.filter(a => !a.startsWith("app")), + scopeSeparator: " ", + }, + function (accessToken, refreshToken, profile, done) { + const data = { + accessToken, + refreshToken, + profile, + }; + + return done(null, data); + }, + ); + passport.use(strategy); + + this.app.use(passport.session()); + } + + listen() { + this.app.listen(this.config.port); + console.log("[SERVER] Listening on port:", this.config.port); + } +} + +module.exports = Server; diff --git a/api/middlewares/auth.js b/api/middlewares/auth.js new file mode 100644 index 0000000..f73c9ae --- /dev/null +++ b/api/middlewares/auth.js @@ -0,0 +1,16 @@ +/** + * @param {import("express").Request} req + * @param {import("express").Response} res + * @param {import("express").NextFunction} next + * @returns {Promise} + */ + +const Auth = (req, res, next) => { + if (!req.user) { + return res.redirect("/login"); + } else { + next(); + } +}; + +module.exports = Auth; diff --git a/api/router.js b/api/router.js new file mode 100644 index 0000000..abeb1e6 --- /dev/null +++ b/api/router.js @@ -0,0 +1,48 @@ +"use strict"; + +const { Router } = require("express"); +const passport = require("passport"); +const { join } = require("path"); +const Auth = require("./middlewares/auth"); + +const dist = join(__dirname, "..", "dashboard", "out"); + +const router = Router(); + +router.get("/", (req, res) => { + res.sendFile(join(dist, "index.html")); +}); + +router.get("/login", (req, res) => { + res.sendFile(join(dist, "login.html")); +}); + +router.get("/api/login", passport.authenticate("discord")); + +router.get("/logout", (req, res) => { + res.sendFile(join(dist, "logout.html")); +}); + +router.get("/api/logout", (req, res) => { + req.session.destroy(() => { + res.redirect("/"); + }); +}); + +router.get("/dashboard", Auth, (_req, res) => { + res.sendFile(join(dist, "dashboard.html")); +}); + +router.get("/servers", Auth, (_req, res) => { + res.sendFile(join(dist, "servers.html")); +}); + +router.get("/api/callback", passport.authenticate('discord', { + failureRedirect: '/', +}), (req, res ) => { + req.session.save(() => { + res.redirect("/"); + }); +}); + +module.exports = router; diff --git a/api/routes/dashboard.js b/api/routes/dashboard.js new file mode 100644 index 0000000..afd9bee --- /dev/null +++ b/api/routes/dashboard.js @@ -0,0 +1,17 @@ +const { Router } = require("express"); +const api = Router(); +const { getClient } = require("../../"); +const Auth = require("../middlewares/auth"); + +api.get("/", Auth, (req, res) => { + const client = getClient(); + let data = { + commandsRan: client.commandsRan, + users: client.users.cache.size, + servers: client.guilds.cache.size, + songsPlayed: client.songsPlayed, + } + res.json(data); +}) + +module.exports = api diff --git a/api/routes/data.js b/api/routes/data.js new file mode 100644 index 0000000..ea74daf --- /dev/null +++ b/api/routes/data.js @@ -0,0 +1,26 @@ +const { Router } = require("express"); +const api = Router(); + +const package = require("../../package.json"); +const { getClient } = require("../../"); + +api.get("/", (req, res) => { + const client = getClient(); + let data = { + name: client.user.username, + version: package.version, + commands: client.slashCommands.map(cmd => { + return { + name: cmd.name, + description: cmd.description, + }; + }), + inviteURL: `https://discord.com/oauth2/authorize?client_id=${ client.config.clientId + }&permissions=${ client.config.permissions + }&scope=${ client.config.scopes.toString().replace(/,/g, "%20") }`, + loggedIn: !!req.user, + }; + res.json(data); +}); + +module.exports = api; diff --git a/app.json b/app.json new file mode 100644 index 0000000..dc0d633 --- /dev/null +++ b/app.json @@ -0,0 +1,39 @@ +{ + "name": "Discord-MusicBot", + "description": "Very simple discord music bot with the discord.js with Song Name playing. It can able to play music with the song name", + "repository": "https://github.com/SudhanPlayz/Discord-MusicBot", + "logo": "https://cdn.discordapp.com/avatars/750613142488481843/e6326038dbe2243ca551ba5b6ecd8bf2.png?size=1024", + "keywords": [ + "node", + "discord", + "youtube", + "music", + "bot", + "lavalink", + "dashboard" + ], + "image": "heroku/nodejs", + "buildpacks": [ + { + "url": "heroku/nodejs" + } + ], + "env": { + "token": { + "description": "The Discord Bot Token (https://discord.com/developers/applications)", + "required": "true" + }, + "clientId": { + "description": "The Discord Bot ClientID", + "required": "true" + }, + "clientSecret": { + "description": "The Discord Bot ClientSecret", + "required": "true" + }, + "website": { + "description": "URL of your webserver (Example: https://domain.xyz). Change this if you want to use the web-dashboard.", + "value": "http://localhost" + } + } +} diff --git a/assets/logo.gif b/assets/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..418966daae9ec0b11a6abc9beef3b1ae8ab506b3 GIT binary patch literal 52397 zcmd?QXIoS6+U-5lAfYBS2{nNPLN9`V6jNxS86Z?Cp-Pu7AZikN(|~kA>CFa;2#Ok- zf+EsIM5KwJsHkA~&*QrHde(ic7yA?JIlsYm9M^A*bDZO{qFNdn`7r?|@J$eaDRYhZS z!_8ZrckbSPI5IRfJ+b+<3e0K(p5) z`P=!PgNOldq zpr*Dzo73Rn=xbm|RMyZ9ia34e(Yy4#i&(s|lWSmi?;O=Fqp+&W+0DZ>s?~@{SJ$N+ z@%8g!L=8^uCZu1}(LGpFdxx2I{%p-u_x)+D{rcvX4&Q$L!vlebM5Nf$oC1%AT3Fl6 zJYTqebJE=_tiHJ|zIe5#Z}rZ-zDrj-7FS+R&HpJbZ+^1yCpG`p{m1KAyiQ1bdE?EG z+=nl34ZN~;2=)rfU>6S@vhp#YM%y?YV;oIkXJj8qzMWsz-r3bNH2ipMVjB2=`@`<> zJ6O=2DI}VOuBJ8w^!GHdKcFx$pbe=1>tz0QO#t{F;0KqnZm;P}gNrIbx$U(BS;FEr zRn{GKLwRD@u!R;>{ll{uO8=7eb)0!2!I`Z$ay^Jrq8%U+KcWq=WrSkQk~mW&At)#W z%%SSx9s@#3^f^pj>r^w%BBDjRk3>6XaU&S#!R^ZsavaFbm|te6f$=xnsz(Yf1e*d@ zA0^zb<>4<1zZt8ygBe)3&$I|kVq^y_mdj+&;G>4xFl?r9-a_^gdG#?%3o}Rfp*Vsl zr$ElcFyr3j;vr(FC!U%xuh4)Ha-tH2nD=|-#1Az3fdRFshio=SR2e2 zGZWq{@$oEKxO?<133G{^XTB+*Bn&3;MeFe;iY{U96|i>jRkLkxX<%vkrpkJaM~KkcMD9em|XPVTrRLg3RSHlH32 z=qMNuozRQ!D=)^&9K10a6mZB=c&k+Vk2D$}Lj%E2kQ22? z!Wuj-&=@C^{_8Tw#JD0+PQX=4W;U$(&=DaLH_A#Ej*9mKtb~{gs}MoTtyM3ZwHg$3o&1A*TL`~oDeOO}@ogbS5%pje zDck-bvo>?j)QO^=6n>4fPfgPNhS4wLx0O8kLfE1Ziuf_D#6j%-dX(6wrR?lbaLP1jw`#UXnHy)l$mls~{S}wvJZau;y zO-XO2csE?zL(LhB?W74PPEoQSN=TqzKNpd`S&=P}?=jZEbqJep=`9w#R1KcW zO3&hMkz!OmDGOGl=ca-2(sayQn@-a&+>Z%>WNET$bc0wFN4S=s!&IudkhQ@v+YQKG z*^6l5s*k=U>7|ZPT+6ByI_*!JYJ;T(7{CEZQrfgJc|*+Aq{xH-7K(xV#9*@uhCw15 zN3axyZOj=v8j&X)E@5ks1?AvCaVHKzqe6xt%-CY#RMmN+GG%&m&p7dbdFEX5 z(O-!hoTEQAD+MZ=jIN9zBYrxZ*I8R9z;HJ*1v-x3yNoc)qTaOutm}{-!Lbp@2lT7D z<=66GuT(8@K94^v1(E_2^Ph2kJ6C@wuERvWm3?@}^+va@CaDZq? zZLANWPjF(mqGYHI&?7U?1}Ud&Ljh37fDu4n7OV|gKur>hAbZ_(1LR;4r3Hs6Iv9vN zRuH*hvdMvktnr$J*#obkltS_b_7prScX{?!$$N0PL_g>X&|y)@I5N~1&1g7 zD7;p&_=5J7>3UP*m61&@4DFQBD$>E*8TsP=;s9u0gHR2#cJpo*zFu%tQy}MNEz0u9 zG{&6(Yi4I7H^$3nLA=qX^W4;L6|haGr@Yq!t-&%|3NjnkEw`#|Uu!OK*36>)e+i_W zq&|Zf%-!t$g`Y%R4X@sM(0I&zzh@BjC10%xg=yl(_TyWx;+%b!B&y2NjCt@~{ZqUz!FX^{EV~g`S{N|_?AMLpspaW#K zwF%BK!P{&%nEz5h^I9pE-|!iq1H&u(_u#QQ9%Akt@v>P*(yUqyIooYbJ99ku*=av* zKy2H{y%hufXIJp%T>e(i=zb_yNeG=-vt_zZ8i2OP-W*W4608+YTm0t$P-Xm~X@iS( z9P5H{Z*n?r9#JPjiSvPx;FM?51K))5m>>YexU}@(!Ve#At-`qUaLQu0<&&s=LgK;= z4}0h8*!L4$>Rg>uFFg9`!Y@+&;fkL539-G?d~XC88%W*}th;scpiDo+y+dOro1*BJ#bO`~>%`pX!MH_^a8oKZWM%R+`$BY<;mKuL>!;@$93mtHz1Quc zhp*){>=ZTQ8dPp2QACKi8s|S-!hQV}mrlAz90`f^ermI5V)mgAy#(V6>uZ0e*k^I} zMX|sH@pKC@_QpHe_n@<3XIy|!w+{V-Rgc!WuJ{}&g?tDNJmqlp(!vLPLCt5|(?X#y z7Op68pMSdkJUjA|>C@i4Q%{6j?QZD>RK7Ux)qnYHMVa%*6A4q7wHQ)%m65)wR<~Yj zNVnO(E`ODJ=2(N8Z_YK3`4_+59v#71JM!tI*6WtE^xHt4r2Y^FBpntn4O+XzAK!K#c|G!+6_kUcJf;wlg4`QMz zV~G6D?Gw(B+#j|u+)-~SZ9|NJ)(+H_D+}P{DUW?)%dg@s^mkb(r~LRMFBa@n4A5pX<*5E!=xk& zb`x9cP-cz7vY(t=Pj0Z6=pVK`mO?HI53H%u%eQ854n!Jlc*fg`*l=?08(H&p-uIff-(T4qMq+7h>i4_EtAtFt*k=&s z-3`0Pi(`J6E}=lOhJXSfV%{%zL?*fglPc|qVZ+hwKpj9C?d}h@FMPdh$-C992p8@p z^aU@lW{A#E!$h3r0YWQI3d%Gjrpa{#v2)1P#~aC>VIvLaH0a9s3aGUXjaPbZi3~l^ z!y#GAHMQae$i0NRSO!W(>=Z$%*j&_nCa9SVN3Ojo((j!kp6_P`0Ts&2%5DvaWYx`v zgWur_<=w3S$qq_qybb_i_Vilea(ajra8hVI7-fL1kxIGIAI;5csVsgVrCF?##m^x+ zSxJUNv&SJzf?Xub8!Mj_pfsssFnKa8-dY@Py3fUx$FT*~+T=3?u{tfYjFLe}4wCC> z8Hq&~F?LV|XwU6&ayK}#auVe*nt9dgRGlL?k5uZ;0hf=OxAUueja(+ii^+iH090gk7V#gpoST{+i->Jry zkznX?^6!!YM_C8uhHsW<<)?pIKDJ5tZXbJRoNBq|Kiy3<2#Ehhygy_5%dYRm1;>w? zTUTix`2J|p-Wv<uZi z?+3B){LXiL0P~pBikT7ev}3w0U*ATes5%m(viJBr*i_-}d1SQGxLV$Kz^(LV0?yB+ zyW*RkZWk*(Qn~y_pg!#6l);Mayx z|8P+snS|_fD{!oLyLMywV~mR-)N0n9BazBuo>X4K3@bsxE@K4}LQ479iTCs|Pcbk0 zvR#PrfMmArA#I?GVNnX!OXFT?^u||}KlOrSA_gI6} zT3gdlz~ugj7_wmE0v{=jO+Z?<=}qBcdig*bJjnWlMAD_+Z>M6~t3vARXdM@@R zwgkJRhd=1@oSMGPUBp=uz)4{?bXt9+W`dgA52mYgEL-wag1+VPfSF{rjy^r7% zpA8eaap5LLSTq;9@d%~6pl{`71oC|+GQE|A0qmb|F!pTjToRjUsms|6%VoOPF2r~6 zsLUSzEpnk2%mDUt)k#I7B`dp15PQ>n%cy$sF>)3t)J4P6kULjg!o}Q7+YOKO)>W@n zui4MrHy-8e#JbcQcjdKC@G&r6%mOel=Ix#hQ$o5wzs)=sk__zetbz{lS@2~2kVrXo zQ1Tp@2%N=VVdfL|VZ1URYBl}QCEz2q0>GVdBY^t2E?rwwzv7F=V~_%kTBAp5$j?BG zdrgW!dCM^eTf#`h8fc!Gq@sE^IbFfODi_D@i#wf-5P8i68(hG>g67k02~h<68MW8xCeCHCtcCiKh|PiFw89UDQ?iwfey zWV?ogTVe!VhmTCM`)z&C=s{0p)nJX|j7)ZuP0I4@K| z;iq#@S3GNM&9h4LJ2VAr8eCR~u_r#e%7y1W%9M12jNFDW9a;*~5TDoy8i06gs(RMB zkk&P`3!ZP|HjcPlzA~|p^yS789bhl$Q?>C^5I(R@qr-LMTQ%``%d4NAN*}-JJ_EPc zfIqpSiQ){&Q|c~VrC`GMTV!PT5D{Z5lub)JrMbYYb~OhqUZmj>AU0fK5Xn3x@0EST z9%Rjux5Ebk3fV+V%|)nEWC?~AA3f}tuEmCfC4TC2FjgT!?o$#6qjvnxYFQF%5%)v! z@-(%(ZcwWe%iOiReefDzxOr3tgeHa?nJC4mV$)CQrT2iLr4^xtRzNF6RlZ#WcW3fEQh@UfVhd z+8_3I9~Dk~utG;i?rru-{6xj{TVN%T&K0RSs-m?&5kL@Ga4DYIQ1VwI8-D%>Me;&0 zgO>X&;m{G8xZ>qZ8NL~9jJv4pjyu&Zs(sxP*`7JTKU8T>73Oo~o9%`b9v3+$H~8tO zJyHN2Necard0;n+zZ7wHVe?@cDXxQlh4lHe#j#dXpXe!19vubI-mFcWOV8R2eOxqk zt2na{v0HwPv>-HO8Jz!qx;_eW(_|W@B`UVxX_!w;=P>48E+ryLJpVdT=MFG3VP{Y# z;%8JS}1&Qzs9hi4F7ccx->Ql zHG!^BZr(%}p5bhuBTwzTfh1fgdq;Sf-(y+&(EJCnNVxGkE#LS8dd>LHKh+yO;pX3o zY(?02hgYAgD;BALwoAT1p9p??QPHE(JRfo_u68tJj(69XOrm7gEx z3t$ajkVJRw*dyzJUj{`IZ|M+Sc2k={&8(^+3P1q`xTvDa_Yu!@+6cV}S~!@~I2__( zThM|cfJ6LLZ|ocpzN`&>ItoYZK$!3i5$Nv|(pSPJflkgE)MZ>)g7affVKpc{>1OQ! zpCe~1zZY-_CjrQm!NGijlb+Le95CKma;|t%twjt3-)bC{0fInZ^$-XNSh38{b0>7% z`AKRiMG`U{N=eR5L?R8S8OAgyQ9)!k!W7E{ARxG#R6Xw01wM1$a1|EK-aqp+Isv2J zzUdUcD!U@a2Y{D?4Qykp8|cjkq}}rnO+V=sRs4Wti!IeguT(QL7<`?sW;MPcVZuz% zP{dp!2NET}k}Ns;)Jr~(!;0|CFR(QH@CEpZLZQp}@*MGOXY?gxaBgh778i(-sx0Hb z4C@GN42WAS--o>X8WJlzEFfp@(7)8Ggt33mD`n|%#x+TTph8na3|nD3wk_&fUgo0D zWZJj(N&tNBEIvc-5z@=_NGeH{7J{3S;%cj042-ZDbt@`axYh;h0geiSMKC)ey%MN? zVWn7kmLWz6UUMY^4F0#&nEkiZocxc}sETcH8AWO^iGN4SU=TdN&~HVNMbyrfp-w6= z&nerA^wwN&e4N8)SWaY#FojTtac>t!ZXC^2(n`Bm?B|~`A+8?|_kKhVWFxiC$h~HM zwt9NWy@TB{-uaFs;xurIh{jxce#0p8_x5}zsH8nQW;&nM6*VjQHw%^o-TIgdC9u|I z?dGi91qmHuJ|@>&eD9ltr7+ZK@SqGyRU3Q9sRu#w!e;y8{nk4|>zRiw+aF6s3V`cQ zs)xk<)SEd6_kVZB^TiH)e`0gdEl$H+Y#fRy{qQt+^`($s&-n z)6%h$@Ksy0iKI!es(`hHy#;reoNp3@A=>kAm-^VdZVf9QmKLKqgH;xef^4YPXtBex z?a}zim*Po9NJLX|2`?zM$GKb|9Zf#2G%Z$C=KOZ852P=st(*Xr{c6whx<~33f9!C0^taeH}xSjk-+Q;Cb>E z_dZz#w+6L{g7QL7D$9<)chDa{&H*PdiifV?H^oTyJQj{cqL9=?t&=vFA5V$EpG*|> zl|>TeE5TpVfs?T^sA=@h>(Xb1>C0k$4Brh)w*jLd;ww?_>ORTXj4Qine$4nKS~~>m zH3!AKq5Jzlr}eY~o+j?rJr<84p>5M!9o;4Lv9ufT167?MKNrs610f>s?nmlthaDbg z=@S_-Gy5X@B*5~5!BpB2Td`e+(RbchUj0y85lMrz$Xi6e=}wh#o#{RLh?C`ly^}Ee z#mO97Hj?KhBj;B9_w2lVXOPQ9zGB_9l2KUKFd@UyXb#GBoRrcJg2xJFT)9h|*F3}~ zf^75t^pH`>GdF3Mwbm@{Zymq+EjxnKaPSBpWZdV8aDC?&hUHTq&iL3bMn+!54>O{LLmSE%(nMu4TAE=|Or49xmia_!wnMSypr{ZIT z3p>vXKm-(0#we*szC4QMh=apuy37y7Ofz2iVIjz7T3l^I)}T&bk-(0X-o1vSiXvc} z(y3}`yU#fFmOxh%n(+u8gqO1s<`bZu14qA8FH~FDaZmu15}RRC4M999B0~z(gHD@$ zq%em%6`!t#3_#{7?<>O^%$lyV{EmLkK?D=T`9jg-y15ZB6OOa#u6*8o!e8pRXM8dazd&p{N^z~(sr-N%p9-%; zn%%j#I156|WR~uf6T4d!kC7ecPf6kY-kl=2nU1nef``M-Qpjc z)IsYi5gewCuMcda$E}KHC1CA|ROb`>p^yceR@-;dHrE5CRNJS65_fXXW^R|G=H5n$ z1B_OHTixEvbSn|%LK2_1r-3n`k(JipmE5`D%^D?=Hi-9LifhSE>kXJAoA{`UBhYQ5 zSYvMu5<+INOt_$H2}F@t?${C-3jMb%=>4}Wg#Jes6x6o^meSZlS7m7bvvHK%uO!9+ zm{x#-X4LrqOdtsLeCrPILo2|>VX|A{Mw5MkTI@Rg(`UB5qd^*&*ge#hu%=83+)pj=PY>ok?dQA^w~RB&b?d6 zo7Z057Xy!$fP-kAt5JxI`7Hk?Ezc!zw?QcTx(gaJ1v>pZ;Sk{ zoR+*XG(6AKF%nM-mql(*3VkZEc$H&--tgoZKdCpEgiSREIQlckk#ue5(f;_pA*lV^!lE7o3jp6dC|{si_vF6`>qlY$9H8t+*yoiHRK&^$Fq2S={3+sbFkPh0yL0% zY|zu-jpAx~5{FIX59AMY#+ZLE1nc5(YJ#StIvkXp8CM-Z3rLH@d3)oFBv@z#s{lUUvoI?cbiB+S@;lGrH2J2_ex3Rlxi_1u@wer)1dVybBr3u|@A#4d)tto}iY ze}Ow*Ac_4ff^^K|a_7G`3VyAF4r+p*OFkhPll(7^N#d&FJ`CELKKAOc(kzaTpL8wY z8Q47eth#smnbx}Hr-kEBPmcAAnkRoxX#V8nnKz_eDZhB@sp+FTceiu!p83WVtw|dXgEsxHCgas;{?w_Y0!^ruOP?B@pwC%?@Eh7L<=$3q34fg?8 zKweu9s-p?~fYBVrSvBMw%!G#*@jKsHk^-tgGvH98zSu>*fj&Z*!FuJh-aQc_JFWLM zK8-B-QOF>JaK`?98*ICDYTg!y+2gB}t#(3Y! zR#JX0C7ZnFI%6-)#PsWz20}EaTxs(VFxOb8SffH}3ANwjU>$lc^RZ1Pne_q=dSO&N z;A(UMovj8?^Q%ojjPkWq?)j&lj4kln!(-)GFS5&Uy~$_i>hzC%9*oGc1)cZ*;=;I;D1mZ`9zP!iPw#fURiu1+B6?Tt^E1Gso zcu~?n@+(TWw7*YW%X}Gr;@8*rj0S-f+cX8YJE=z55XDwvbJ)$>-##u4qD!~DeFYHMS2+aNXRHwalivocvBWoM3OFfyDOOfYdlE5N zF-`+icyd;P2pWln$F;o-(;^l08_pNVySk+XcP-D3^N@oP@>2Q9M?ER>bF*R;ZDNI^ zzp4wb1z_BCKnc(ZQ8}7)C84KEP!Xl$6^PKIvnqBqo_SHuTg)pTCc3ca zAq^Vm`ct+n@h8uqHK5+QPe@O1hXT_Hxac1w*c9|}Y!A)|HlE!{g?5a0QLSha(pNz6Fi^2+i| zriG_Ijm_ouY>VsokrHHTQ8MWn{4S`2XV%!LuV3GN6qJrm0q(58@@7!J-N9>7FWMSq z`WA<7&&DKH_q7Tl6?44q?j_2&B+Kn9)}s7wdu=&9%2qF>5svIcJy!j63Gl=F?pTt< z22uw`4$5bzTP!*aW?Llec)f`ayix+`2}@X>N1LAa2!41th#p4<>&4%+IGrfdXMHFD zYB_C;3Z=`dnR0aEJS(bE^Nv0CU6ug>>4Vm&qy>FTOT9h1qQwz6`tE(_rzbJf^+s1Z z`~2~yFDIO8dt4{P1??Tj#WL>BKF<6SVQ8Z}HM#{0|MlRhO?%?DTT;ujb{UUyBW0aS=ZQG^&*U*~f$b6_rb&u~gD3%M1Ks09R9>s2!)nfp~* z$Ta_!QaMc>6CI{&Sn7@JCg^fzbR+m@!!BN1&4_jb5pr1KZxMeJW>=a4pf-w27qeXqd+~ZE3)lwkh zm^cTNE`XKY_FA?7Jkf!T2t14Ur?~}+)D}#@NKzx`TPc7SC?|8jIYnxEOx!vbivq7Z z!pD*C_4HsT*-oG8bakhP&6PWE6q+ZnnVHeL=T#W9go0Q#V2fFW{k}}}Nw)b)!!|7E zI$ud2L3+<;LNx}+Fm-WrnV;rOY9Jv>I~pz8u6c}rcq4i?1^KYU0WKuzWucyaxN(UA z)zb!?w7?mKy$l{DOdl^!+cj4P;HP4S)v#ere|v%drzvRs-|#;EzwnNq0KkH1Nx&Mq zJ6;dQY`ots1fbAy#smTubACHM0VSAIH?X0N%$6p>m*E>cABNHLyytsI-0Gz*92 zoxm_WjD(6!tLruXn)JVqkr+7ip-bHe^t*p3TlcQfNZeVuj_Jjqju(OhcpO<03igrEF|;Q-7iF^X4=hBN@4Rt zT+q!fX^4VU57?2aT0!$6zi;wPpe+v_cC9SasSwda zzyq=evw#Z<8_XhT=oMl{aYE^v(vo(g?PfG@E7F`_p25U{$nAJ`86kI^6eL30CX*y; za%dvPoM)Z_=;S?^M1TU{H8!9?0@(+e?6Xk#B;m^bK+rj@(c^pHz> zC(lR5=h~Z=B;LjIg)S*49mnf^`wq_aM3yI*lO9S%(5^ry!aEXKQCpuL?km^-KnzRW zs`7@ofQm)s>?2~yS-qEOL)(t$3!lhMs>ekgYJb~Ud9rsc%f~2nblA!z*kbhv{^($= zB{T`jOOpJ!wJ_Y9c z?++eDq7A^Z_7Eyy-8dv1+4UZLl>=@!dbTlOuXCRCZCW_}mX+vxCO0Y=bYgrX&GEwo zxHybs23tG*`Vv{_R#W9798L6{R^;rHWGH|(i2qzwI7B-c1|ips38`#(*$EV7>xBr1i73eTC)ZyZRP*UTJD;=69Cca(`_-w&H%4b0*jXcJ{eawUb0?k?3P9pGyC?(-CgiZh_css8R&n#t zp?!doLi!39ddk6k1YKW_6sif#3P`mb_FM%S)#)gz5}zi0?l#Z>W8kMphsBhOAOZbfUSZXLfrhSeSR7iYEJ4XVu@5iy9!R1 z{!mJYU!%Fx_K169W@&~wLd&<+x;R?6+~3*JE2W|^+b-~2Rj~&uc)%{B0muO`OkQTr z<1!UdV1G*!S=+FXH~J{1ZQ;3rFH^Kk9l#R}l_7&o(BgLIDnxRj`BmC28A5S0%l=2O z;in4ZQJV&Edk=uS;`%hFrKValnZ=LX03jQkjiaHDcxbvJY^6Xb;d%eZ!LEs%g>&Vy zAjKP;*OaoI2ertPBYBV9oN`R2>*3V=Az&Uw=@V=Ak}kH@Wfq;U6T=>$5@$<~x7R(0 zSA-zXBhQqfB(>qn7W8a{%>e18I8;y+4Y=Moh#Yk%wknTi9|mbN$qW~a;#}XkNxqx1 z+Dp8IKBmAH5dsr?O8HM;>HluT_1c*{JS<&pMmrJ0wD@;lDS!-t9ByzYU2hl>2djg# z83Xl?%d~yjy(s7^Ra_M`NRS-pWBp}0-_1~w=0^euMFHXW z4~1X3qN;+)uk5Rb{JxmbCETCJlfVC3Ej#)#{1f-j9?*Xi%J>Siu1)}~IWL7&|1g%) zmX|GG5l2R5Wq4JMfaT1X%>%W>7*vf2^hsl|qo7RFM(I&`*B1Fmz7~34*4AAZ*+!z! zTKWvYB?c6fcqe)~NN*_-^P+RgS3?cgpc%QeT;j9zXnRJjzecJ!zF6JqM`;m&WL3CH z$o^1_J?7CW!k1fEBf@_)tYNuyIT>g=b3!Ks1&+7e#9DFmVQx^PYK~-pM1qPpV4Vwq z%l$tzKDUWU`6f}TTG3vX16aGOaO9vhP7R?wnAPS<@3u)mSu7qbPD$Ns9}t4HG(g&T zhQ^y&a@%uEBGz5|99eAXVD%CGwN5Uei9V{%h+<(>fv0BgW_iB29ElXww1`Oq&u6M> zp7bvc|Io8h`3^#US@7<|9l4v>VOr>THZ%UP-b_aP=_|@vE{E5k%sST1HP3r)D244S z+o$F|2hdnhc}1a4N|oql@a0brHZzw!<&djk(TwQmh|eP%{e@F^vHJ#xY!UE4^T&2Q zB>7u<1};OEL4N@xDfK?Jgx5$^;U(H=fa5Hw{EapvXY|8RqA#E%;`6AP!S0(BQ>zCa zvy7~ls2R5e`&YC64+95BqRlP8I@w(6%(ALrOb?9sncKSx-TAr4WA0!re>9#Uz_HkI zAva$sd@hN<`u)y?AQyJOX)hJ+QzYoYN;LGH5D+X8Dto&dWH! z9VVAiar9vcWrq+469Hj3Uk2Jh|C5GZrMJXua7NYAk{&rCPyEU)R#nTAUbrK|kNdqA z(jA?DEJqsP(U!sTEuEnql=xZ@Fmu(h@x8<+y4_s|I`B}yh`PrA z%(+JAA0nO@aR!+I4D%-Q`Ex;B-s^GJ0G&x`#@UKKNGiisDqBkUkyQ554rHUr_{>K_ zNy^wQag1-3HBhtm;2gpEg5EiB z!(TQBu;U#?h)`*v^p=GY(MCiCG3_eNQ549(V0}*Eau20ts$4lY(a=4uZt{{8iqX2c z((1-B4ijlff?ax^?xvYNM~feP)+`aGgd*L#>V5mb*jw==AoHb~KE5|$z9zWfPWHP8 zb0=;xxp%~KdC)R+;uHS-{nDx0+nVsl_(QZ(G_`Gg>LCB(N!tFtjdDtur$zG8&e)xU zxkX8TbR$OQRgGRaB!Bz6mhAN=x8xk{{xX)REap<^HNtgVT^=ba~U86>Ei{<zU`cOd2hKn1kstix#uCm-{ycI00<-< zjG%0_5AZ6QAefMwV~n&Wv)SWS7I+<+dB>^AA+o*lYnVnryf=~PxRCfxgFoKuk{eHI zZukdMwHQ6)7VW}cHt(~~K+11ROhc~=JUUS#$|Jsg`S_clu2)1;Oe2#dyA;mgS^Tq9 zHL$DH8R!^Zj_19VYkB#TMR~0OJb+J3UpwGNwd?i+f^WR_BWQ-PKdiE~QQP0@`eh{Y zrmLg+K)wYd&Z6^zD~~1bo_ZVjm}KOO#*<_EH@x#&i>VgMYGRg-2MOM&DbM3~ogdhs zE@4HQO@S_tz(ZN)j{X-Dx}HS`3??k>54_?y1Gm58Byjk}Udf=3$tAs8ZSK}TEGIrR z1#7PSjYe+8nH{>o8EbPz5T|_<$8UMd?&tZEt@)z&`kK`06*SNl<0-Nld@|qXO~b%r zPsiBun>@E1r35=7?+BOmtuLVmQ*4@^YJc_s9da97`0d|#Y)g3}Z~V)++pDR;MJF@b z?R6gHC-M7`i`Cz(Cv`OLZ0xgOj?Rh(zPG%QdyMe}{z>CL%c8v84A8VDQnC|5eMwO; zklYp#gOwy9Jh$1kfvq@LT^@jlH3Oo#D(0$GKoZYJi~&%K9+orRu^2{;W}j81+E!g> zR?2WSt)(8v&C^BTra{p4o{Mmk=pxGIwgv0cBmTV*FiEmYSiANIA5WMFQ?5GND%bc) zgTiic%XB&zG-xwUTcOB;Yb}oRdeZ@6|hfb1^vDYl5O^XscVs*6`#sn={smAA@j|cBc8I|I| zm5-1C?Q^$|OfU`h)N+s?6pUta*7fNCL+K_@f2BFwKozsnKDKipq!9@St_kv%m$!S^ zw3Zhf44}@RlcCQvkROi1 zvU$NZd9v!(V*0bSl{J_uHOXKqbSZD}K+2T&BPg(cAatmR&aGOxE}z!^MkQ6E3Fp@S zH(K&g&j{l^i=R+5bHiLJiXcMw5uV*49OOintl3E82O8QL4^v9=F}vy`fd_7b(KNNF z;!doYeGO|l;R%nBr|bboZ7Ba*TZ(=t7vcK7Sgf20m9xtRiC{noB9lj=9U_RKxhTlE z*!;&k>-;yL1OCHjIT_C193%@G%HXtPSpEOgpd8kzJC;$*L zbRDju-e`JKX(-Vh__x;b5JL6>k4N8Vajeu#_a`mgXmw_RWFn9{q!w1ad*lj|kN9xv znu!V%Njd;|CgCx4^*ct7Db^lsG>@?@i=dSmPX}kzbZWljkAW!eyd#D{?pnD-H!j`M z6zJo?erEKQ2&~lMyAwmU%E)Wn0tj3-=7$n*t-9GIIj?V7G=auQC8TG-%}DksHF!d; z!q-tTue*y;Qj7p^yw|bsrJ*~ZzjE=-2yUH6g4QLhfRMD8& zZclHyXbW;EF8VbqL(+)5lwH-cF5*}g%8||PnsF(y1s5mE1ETG7{vKYnOn0PL5K{8^ zffY+P&@}czsqG(FtEacHWM(;xoMXLGT=2YRjTpbVJ_+1yZ0yg!;Qa&bjgeHKp9*!X zttbzeY$O(jzJD_*9-&EKu;mMcHL_04tFY6^7D>e*vInZI8k4;)!fQa=(_s_kQyG>B!UE=E`9Alz z;ohKF{8qarsON3@fdz}L>p(-|)=}zp`tprw*E>#;`({uBe-jZDMQZebpN8$z0_g@M zuS;xt57eUOf~X1llOsvC{ZbKzbu#IEM^}R1HR4#?v*Dw2|6Cfs9sMKxe921{#x@CR zqW)=6R)?s=7Vzzr3Iaymnk`h&(MNg;Ge{TjtcR6}4Ey?lDjpTOd=h)S&trV1EigUclj=zdK4_moai%h5@A~nW6vt%he z2erxvgoCnp!EU-o&EpP7QqCtPX{POVS!(CKEFMWw+lxQWk?w{jzOoOpGxU;>zxutz z%Xw=%%pyAI`%%8MjP3qg;_7qUo!Vc=UUz-ERCzCYnP2wlz|0X2|KfG%#}!jq#}U$n zfe)f1E(U!OQaYXYA_eAs8hYLjHtW5&nYd249jUJU_%bq1Tx&djO!Pd&dx%$4457i% z?iVtS-tI%vt7__OK{U@^@jIKzqG!eYkDc(-q;g9BngGn+$`!sLimN1&5A^kDJy^^y z3b#^j8=qb>3b#N&aSKg<3x1b-89Jz~7vf9B;#<*enz`?onbWa2K$7jGfIL@>97dZ& zj?g_SIJT;szV-=W;Oo@m^Io3;q{ta-%^!gO-WV?v{C(Tzaa^uPdOz`Id5x8R{(K$~ zEk4-70LT>pKkKHds9>YsMKCbmMPNfRR4Fgi3L4T^Sc{ir9Llm*QZ>ryp1>4kV|J;pI_OJrX4aC%&NUfs{TS_3; zCK%3sjkaD0J8|3)-gAKop~W8TfFyO8EO?P5GdP2JJy0+y`c-T+CaoIj0O-wugbj7m zSk}yolcL#R9D{WxWg4s(!UV4e)&Ixt68{^gtpCL+bg7O770?YN=4Z2bps;_($`8{4 za+r3Zf5yL_PBm%kj1N8hYj;z`Rxp-lIDp}>SjdC^v5Q3010$Ha4QLggldAWlX(%s< zRBt2e-l-~31)*!de54N=Yh@VA5!`QvpsE1RXz%l%p`N^ctEbe}$nY`Qh%Z;indgX( z(yA56JQNG~?^k~|kmsJhk<`#SHVzfc&O_szLS1ChOs!u_? zI=nN?zS)jd`u`F3=KoOlfBXMyHnSLvF&O(;#-4@{qGrYnhKU*b9it z&k#8~c&lZ*rWD5a1`>iKtgL@Iyt4>jc_p535LSisGp<=}C;u@HK%akJ5PjGrx25!> zYe82Pw|@X_%U|A(&q)`YJn;~)I%=$!;m!EH;-#cJlZag~fAmK`!}0lHD?yVQ7fHvw z;NfOcyqqAvMnL}RMd&*IZDSY+5lI#bPapSqA(rLO+>mB8F-s=ac z2~xlTwqPv0lEzA3c zx9v?O5d4K;0ta^ZmAUA&Pr=1i*dFMI_A4Nc(5RWxk@l`9@QVIt=DRg zyoa2S6klyV@+`Ku=a1x%`8U4*BZv55cfj_HnxqWxoMr+5Y8{0vkl|YTZhUY>RU=i> z6Cuu!(BMs}0$7CzJB+h{KIosjASQc7>mJ{kWwD?GC>@ZOB!kuhG;{%lkco@&)SK@? zcOYNoPB+fEH}mHNf86}Lym&4Q*iV^qsbvVtr?_Ws#36ytJNA9n=P0PI5TPdwB%4P7us*Z9w%u*}_V_87yw4u=;&#*5Ms*UK6EhhbtUOq&*K>@lIfEMU4_bdJkCD zixQ2e@bZzTijG_ib!zQY{S6bIPB;#@qFL%s=E>Q6ll|8L0qDadur0T{Vd5!*^WE36 zXvx0u!O152hjsw+>HNfldtbCXI>>*VlwEchT&bT^;_>iWWd?9O_H%T1V2?Qh9FHaY zyus+n{E8Sh<0w!E5@B1mbr4|a&V>ju!Xo)CuSHmsK)yr*2Os zpU>LzTAa5@^45<5S|8LAQ+2GId*2J;@X~w^+g-z61ia2n|9HfMQF ziORDF%ncB|2J-_4*(Dt>)!|mL7M|T%FRtQe{|TyP8=We#mHuOI{i6&axZqUSw^j?s z@zRpBcUY23v2UtudM*ZEdP-rS>oeRWgw!6I!4rc>ZU#3Ri{3vh1#hyipUBF8i$0LK^W1EvKkivh>+f6VZn}bq z7vhevv6SCyHg+SdaAB4}0e$__Rq-Em;|`7AOcQZlSx;cV6;scla}hIR{KA7VtP;&E>YXNpV)8=;=~%n9 z<}y-jwTFZqHzJ0?igpf%$Hr`82H}ylK%KMU+9<#Eyz{%dHgBDbI)Cv1c?f>0T_}q0 zh(&>p0ZUUKTAN0EGuXs~g8jflHS+4Uh3tugSCXqLr{wHr*({u${#2Yq-*48esw<%} zIC5>|f<(WvMb|mWUx)m7lo$kdO@w&-9q7u{QPoEG)qm)8AmBGf_8ny2&=V>je#i6A zNliaEs`i8vpwRcx#f7|$Fe>{?j3VMB z|EXG?pZikvj*<08pt6mf`<4DqNubC}nj}PGa$FU)#K+G1^>&}hIzGy644o48pRqW$ zmgIHo#i!xt0erb6oW;&{RR4qt<^8RbEa)kp%9U#;UV9(wTgW-}Yv1$DC>_8dLHalO zoT-kG{=uh-=g+yi27(S`8EBu9tgVR8!P3hCw(rO;9|}iDs@lyzgX{u(d;=`o{Q_ru#-C;;(CXwnLr~ zQ3;&1n}t~Nf`yy7jekC$x zQ80);1Ks$<6ihy7p;I*rTzjpR-8aLpuGwdCd24tr6PJXZD#fNWFhK=LyUg_&vMqGJ zhEHLOPHLDQu4(vgVQYdL^-HPbr+zhmGjRp%xqtgy9#+*RkS3KP(beq*5m1BU6zhrvP)vf~0b&a9C?HX8^wCwaVCx(rrI5r7FKFfNT&g3f3` z*o2s26~dv)U65oGQie|1{R=Qt&h=v<@H}6RM93x0zsCL}(*J8jMoWhiG64cGa=x8p z`w;Md?r>np&aF3qL?jKs;+i+cwjwe`#?mFV){8nk`K^eIIFBmep4qy?5v@wYvq~jx zWAR&_ijf8_{aVk?D;FQi?<840zvD%imDH00mWzAZ`~>^lbo=f+GR%{Rx;w&gzINzo z?!m908o%u5*jGs3UyBo5Bi&QOY#KV?e>6%C9gD(S_4j=dHjrGwoZ2&)ZrK6e>$$*p|k5e>z~F#?kWXuH@QgL@$sn*Bl@J^`1eVvTN!WD>lbuDm|=NE z`pGX@iM7h+9=Wdkymy}$c13Sq?NA-%ly>yH=piG1r6~8^c3ay8x^d!xx_JxB^RI9$kwdL`T-gQV{VoAmu}Ii;SJK zkr|OTWqs;7)lFkn$ZG3_SEsb1Q^8S&^QrFeo&R{1Y3i{>O4)jM6&v|FvhnUn{!Nk+ zjf#s_Om;Ce_W3lKakPc7Rj?B!rKyl^&U)c`z24f zt}L5K^Ep8Cf!{!pX8D#PfTp5Ql%XyWmU281|_8 z|C0XbIfeZFOA)f`S@{!2PFi>pD|9K&WPqG8J?gS;bD4b1bu^0{LGXE#@GLpW3#MTb z6nMnJ`}3xnsaV$IX8ePbb;}`-QkCrD6F^BRv>Oig2fc4i%dh#Uw%=LAX|@NOD!)oW z$|lG(dOM^px-yCe9(;)0IGE6)cw{@(;aBLv4-a%bAuBIsRi3l+E}7sE(F2ARYuoJv zPcY#Ho#e|?koe)o8_)C-lgaIOVq77Yw(_xKGPCoHU9ZA1NPA2|35KK}O6q9#-p-Y( z4izYdVSbZ5eh}8)86G_-(f}}>dzK!C9L=I&0cpY>BWoj@kCgmSs4uaE26t6G3Vg<6 zw1?0lYbhPfVzB+~(lNkH(~1E?^|eFNKY7-GIg(gU{0`0(x3z8jJOQGgi*L}+lDp5? zR2EcYqa|`rCUGK}EZW`ldxveN&{DDc#ih0hhyO_eNypl28+CUcbhpl{iyf*iOIZw)T` zO?*0!#T!Hv+XRgk>pcOmE)KShzZ|T$PZj9O7?>{Gy|b}GE;HsGolj;QCUD9CLl31o zZxiFK1x=X4Vr2VsUD-q%!r90?Ir*iyQWXzLfPI1cm8^5}vyl=ln>-n2BL_^y)qtH? zcjcK#K+&nHN&FBvbni>eBCYwsoi8PpTsgzGt+Xy52B3s;+P9un+Dh5m+(*rSB~1HA zwZxONZxqM?-`HUFc+OW4#%VGCb;R<8fgTY~5R zn0euw98Yd0FDpAIH!qjE$5UEbrq~)N10?b*tEy{i&sHgBX*Dz`mZOXe^tk5dE_GZ! z2dg^YAXknt>K`zobl$q%DO=N{b+xR$N>Vs6$x{+fO`n%3H@p7$vF_bx^OfS+GUd6~ z1L2ye=kK12(d8QN*VbS3z{~BIehe6X`E^PBt?bjXN}rav=_Eou#m=-epCp~D4r=Sgzh@_tCFvf>kM!Ola3<*v*LI3QBGBu?rvq0{i`y^ z0}y82QksxPD$}@xFGmxGv-bm&QhW1?4Cw}<*#oo?@3D)$-bAf^DKVUJPTZ5QYnwA2 zEC$0#HpXS%tZ=q|r}{Sd$p_9Hzw@1o?A)OfYTdKz``M*B+QW+tB>=Hv zak{N%|9fy({dNeHv}Ja4rh2rgc$M_tS0VXv_}lzFInH{K%`8Ap>hp_TM!l8D9;{r2 zOe3St^{fr1atEu3^JFFM@cHtwIA&<6JD~sK_)x1kd3fYOIr&65`{u3R?*l=IxiQV? zzeax^rB5MA@(ZF9-$ZM51hthA2<&5Wd9KNJj1NOX(((Z%xML*@#2gIoo0K7yM~4xy zm5ae9I-a_(wnKj<%Al6tJrLsAJyGx8`YD@I(8=29&dcmQ`zlI z<(O7%tW)j9_ZOdub=@wuD@0z@Y8<)4Z0$^sZPTntOq5`T=357~w0yeyp=(TccE#wF zdp)3XSJwqmpY@cCgbhAYZ0(tE9*LrQdzpc#?9>maDy!+3Lq-XMU*9+`um-^{2S&8% zSO4_dD6T@Ja1NhPs_a{K+&Acc;F{mDL}E9gv(w#XIbV5kD6ecfb5j$kSEI4@e?5LZ zT2AVXh4&)kxhPv$qz}aB~94!1ZG+ zfT?Ti`5LzA@Ehk^%nrM2-%HunJNxxyPZ!uox{=xk2no*JtX~d!ATztNL9eJ%BH*HP z^@gl83DouN_Q9*z)l%l1ty~bGsz2BjEo>yG>X)+^!1>juqzAjV#y_C=nZE^~N@&6n z;o+66=kHo@~tk^?^-HY@t79uk^UL_TJ&y8ZZA9Gk za&DI)TDX1NvwA4VYOLVa_y|n%M=-)rc0eLO_UI13(D#93JE%7#05oB-3%8b`IN5ll zELU3UKwrKyqKiv2hVu1Ick8IXvcA}WlV`=}u32<(7`9^wiTYa~gE;n#RrE*oH3VEo z6AsTUjsX7~D)ql_@Zsy3AP8Jq-Ii0SlLJ=x_si&M33@JWJsQF(1;|^6rV?$3)7o@z za!kkq0*Um0KmVj_B>P_`E%|9Eu`p9L%`nIiGd9)YrX-l}YPk6DqM>t0yr`$`aRFII zpxRJ8%Do)@04&cbp*d>B+}2uA-m;SbR<^Er6Gx&Z@#dFN>gnI?Usgy@jTCUYL5ri@ zeX8f?O`9QQ3d!E}?dz04fi)|U!~Dxo30>njy+|-Xl zraJ_xg0P*d3UPlxG_1ddgI_mA>5wnf9-c%N*4v*1Egs5vAM5D6X=m-fD-?MoivwIv z(*c)hOv=28_u+WR%FR7cQvxE8KYgSUd;pt`Wxx}m+bTe)&1Zo*UghzMfZ~ecIfTu; zmnuiUFWv{L5ZniKMv*JI;3GtZu;W^RsaPrCVy7@@PkY*;Oamxd6a-HT(LQzQtT``z zqu!GY-*Yvm=8reXTx>>;sB@vrQ-Y}KtfG8m2srYD6_LR>Bvy4ciOv~J*5Au&ax%=m zFy%x)OM@nF7aVo3IrQmq1A8hZ$6dNqt@Dk*D?i0O{rb4@Je*gQ40AL!H#Fe>KD)6m zZdcl4QKOcauSa36utZqdviBizMa)W3i>-kv2%-eqB#1CF)a>~n`Ob?EU_Q*150|A_ z6uy^LTBU9a*-lvtW@A9$du^Z0#hx2DnJjeIYZriz=^F%mbib$Und6|knmYsfkRTzx zhOE~CaAVTF9fk26^A3t049JYN=xoCP{eK;J-3yK?GokDw5#ed@kzHk{^iwn)L<+jh z1gcXolcjv*ZqxeVTPF%wc&(OfHRr&xz#yEV&j%=F`?VYH+GcV(V(pyY?4**zB>7MG z)J{BhSIhzBE1-`Qqc`#$@ckQ(du{FfZfm;V?RfZC=(ZGp_TigskiODlZ{gpu%w!kp z>B6b|w%^*XCfa<@`a0wMH6^~pRI=>*GozNxtF*fYU!QwDC+8TaxqPlK8(DnmKl#Ho zEZH=4NE!|^1*ol8*W8O_lCRx??z#7XX?Q>_q6z-|1N)}s3!k4(tj?5@v9InD+15a0zZoDyDMIC5O{ zLGoC-Z<3xAe_Oa7k4$q$fiChM`xMCsNNQ9J&|o&?^;CGs1Ut@YP3KF(#W>}zbB(r~ zT|kJ?s>&u$fYvuy9wwSUF_pdskgY{QCZKyeih6)4Ua@a3pi!?{-U$aFvv;hzA$S;) zzO85riDcO~0Wbw;aq~pTjzBr^=Ie$`=d()|PwNMR$OLRJXwAga)D6L+0&>R+GmaE* z-Dx-_8omh!th9nFdS2^EpJeY>Fdkc0z)*kU0iui5`Pi8i`H?9o9CJ(*bZAc85=73i zMvqQ`%L|mF<}URW?{w!$Yh-Z4j>F-(L^RL+>6A)O2l*VA?4oeSq3w&{b}K)0^*G*2d>YRx(j63NJ%|S zDlBufKO_^F6KY#Nz0bo5G%>}wQP4q-#tj|Xf6n;-dklGN^_HZ-Axf(H|F&7p`?8_A zQi{4HK-kqdUaF8Kz==wT7=XlR*gE4!j#L=yiJ6^)P&mvo^XWY2U+<$%^a7qirT{4g z<~g6e*rlIQX)B#AxYOH4sZ|RDle-$){jPZ4NX#nkx%BKjE=<|V<#BrzEcWXo;{hDN z8{qiFJv{J*@}j{wOd5$!%Z3f|+peZ7$-zdU#XF3|M=2esk%E2E>c4xNGApsH0fL>f z>7y#LpX10oN;`6@Z{n8Iwi=SFjVUbs-r4IhpNE?F`xEZf4kh$j$%yAgwLc14@AqGA zSNlp!ncuD;+?;gnjfkp*+{$#-+^u`G-bzEP)3BQ)4GTk((hl!9#+3f{upE5SRJIfJ z$L}t&8j}c3Q$RrnX>#6MRxvp`)rUz#(pL>nOqLhbud_F>w`PV96bc#5s1!@ z_AOTE<&l|YvyZtsrfLhIO4DOFGE=+tNV6}3BaEyeug(%xdTm3`fI=u$E$yE>qcaXG=q>rHwpOlN80RGaa73(4zR8@aSUu2vmfCpWRH! ztS}8tFuaKLB6)xlz?K(%_sr+F`A8v>y^(EZgw;;yi7K{|gKhB?091TCz_i9V)Ccw-)Nq{H9pd9 z?(7PbV!0^S;a>Mh|6an96q!Ft-6w~Z&lFl6D}j#K&+EN&RtMk8B@)@}f z?QXp4K3Zc684<OhNz zADu<{6;QwsJbk2EG9NpF0AMQ#_6C?!@Tkfz^n$FeWbXOQR)PZgQgN6{T4T9+PlNmz zrzoWz4>9lOC?$6re|)Fy>a43^8Q)#HJDs)Gdbj2-n=--!|G`9|TOaFxggKlu zon}){g+Wr}4-=4OEUP9h{VXY=Z)6vl39g=!vJFXBI!;0At&N`1yu`YLTv zy``U7+c!|RoO(arzoy`3jGvq%cxn2mxV(t=%$viO?vQ(vx6%3LKJtUZZfpC`LnGpSa1By z2_t@|2GH{DjI5jVnB~F=ja5BBnc|d#-P@r=B)gA1(NkB#uI2z3%LuZH8;*Ns`hISZa$WsLkaicN`|Rff1nRsEjybK)+HF~1g9jI%EYMhAPHyk zQ(%>D%Q}@RhIyep3UVG(?n^QYpaqBR6}FRO7(_=30~WHK!tP)kW?x*7yYCi17 z*sQ(k6TE46;JN)xO6m~Qg-9Axne*b`qN=Ua_v5T1?5oJK8y%iTGP^Q-kDjgZnX$|e z0xQU+Xud4(aI%G1JrHCgW!TPdro>Dh^jKiLCuy*h!=pU9^!9Onx`8V-Z;*GHd&y$$ zpj%A*1Ai-!_wHRiBScQfgj3tRt53)wtXFqBp`Ob%QV}_I(D$9>IbsF6cUKEW$$YIv zwyEVFYG{4WPfnU~gT_}JIbG0SxmSPd!{Uc<c1tGrzZ zgtCqTOaO4@8MGVZwUVZz3-G^-g_0~^S&B7J&vAmx7Y}Cq9U_K)&I3tr#tiMO!Mhnl zSn5(n4HxP#oGdL;b)xjpO`>-r2cfJr#=NGXH7U$d+9F;~35M@8w-L#m`M$=i+Z#bN z=dm5AgN8ZSJVB^ELkW;U^vKEsAM~X4wTGN4af)S}(<-vB-Sp=M^FKy`wvm?{NPL{a zm~1$MEk=vduoTb&=#01#jp*T)m645=FyX@+gz?fbf&mq=9G=}=y3o(oHe3sr3Lo!Q zn{y+!Fr5v(j+*Uzv{b&QOUD$J<-=$JfCf(Sh z+qkO=qZ$u7<1npDFs)ojZ-&PCg+nY^il1@Lqo{Q!f;2|u;Qv3LO$*mebS%k`kvL=> z|8Ep%bON^!t+M04P@r4RE19QGTh$*Ux=OVFV`Qzd+`(*J>5g(yv)Yni!yTCrV0Wou zieD+1)8ca8`EGRSum>R3?9fZ;Y4fQy?Enk98+hPLCPwK&6W-#}ZBf&A9{PLa&1o8a zd2==+wBu!k#p&H@0_x>Zxr9yKRQ88RXe7VHi z2NZIfiPKl^oLq}rOXV+N*T>874in!?og*J#+V9M58oX}hP;K3zOxS3)yUa_a!`2rBoLz(ntlRQk9Xw#dPY69>g-P(@>E7K+ zs%dvCa)GdV-x;QCu7&-nZU*6z2X(AZHm%VvLb<4>Fhp1c6>kL@aXKqHd*yC8GzM>< z>eL3%I86`OZg-*_cwldpqC9d{A5aTQH23iJDJC_c@PSqKaLeJTCM?O5Bq9f*%smp_ zlvwzpo%)^o0h|CjR2mG@oGOnrBZJUkS>#3upMMsjtHIwGGa*~ptwFHQr|}pUU}~op z+$XpTT=v2UBf0X49fh+S;5ng%#^tBdI_^>5OaA$?cr?MWQIr{hTp zC5PeSEm^kjVyw&3Ghi_lKIJ|(0;3kSA5FqS-7*7jkWoSaMrHS1x#7z_m4|YC@S6R=d_JJOl~XgkEdR${Hbw-y{7Bm$d!U>=f-HoZQEn6&&wHsH zzzvh5%D%@Pf&AzZkC~rdJ#g0pNg5$T%g$sbneNAJIGi&3iyuggn!Q5F5dPTOpfzSq z9k%^Fo9T;py!7qSmxk}2G7PUv)3X7N8GZ!#wzKRRf1;=rLE@YD(38IYdF4p#X-(j< z^YhKg?=SU+2WBVj9)6skxR)o@>p;!@_I@nxHPdpzZf}R@oifMrUKxeI>0N=zW;URL zlU|w?80n;EBCgMFS^1mh9vB_ZXpn6;939BW%nQ4;D7Q*@#u64u@UwjaU1X2G>P!)P@cP+gd$D+}sBAa$H~`2#5bGOk>?*dqoE{?O5oK`C5; zgk^wW_=O%`3<7aj+j-uV3R=&lgE~dilASP)>Lkw%QbmS^2zVw5O}c78neQfcQKTS6 zF@~3nKU!f?C923wBhst~Cf>gK0v$>pdtO9h(NxRH#&S-fT+1V}7;#9d+Xe7&t9n)+Vri*<(i_r zv3>KU#oL3I!TpWRWZmdGOYlPBJI@wiZBQMT+k~`Wzoi_)9Z;cc!PXakcMA0Esng(*ihmJpN?a8JNAi4vY_h-S;Z|Dc$||HlZtb*&2j&$SAQ z;7Mm2=a-b0l~j9nwHV_b-k&mk@chZk?y1{*o=Z>`R@z@FJ_l^ymBxbua)BNX~%s&6=?t`uSou|Np>Da87 zil|jCx1upf()*;`8O*PDm6r}FxDwAXzdx|;7#-UyN3zE)k88I2U7Y&U_sStv>Iv5Z z@Syof`AJ3&xM4gd z9 zMk`k0*UJjIQUsLcO?;Z90@v`B&bDV>v13g)lh+xb5PtnI-ZtzDuX#Z~KbF{}OcfF? zcH|?l3sW|^^4(euSw?o461lkBsF?#sTVVo3N9J60VfP3Y`=KqT=jp0um+QpDg-RT0 zq$9*BAg^UOPGoSg%Ky4#(@lLx$wq;dA^!XxFBfFPL%cJ(p8IsdMbLVy#|1v4-_p|G z!T}y1c+mXn4ivf(nOl?8ZE#Au=ceTr0sRy9*SJJ=uYES!%G05sVl4!j50}w#bb#pT zM3#3k!^|>*f3he_RwupX;)wDH_H(%5yfH#L8^_PWH!S>686B4riX^FWiT5;r_z#AS z*C&(Q6S0CdB`t&2;X66mOXn9LdIr&W9mCRb(d}kxr{7gUK(@O4`yW@QYEKOYR^rO)-zIn z+{=LXh|&BVQqWxOEWyIwofmVccvmp2wPr*iINJUdi+bY092vG9YjdntpeDVb=}?U+ z9^E^%%c3WAFUC|DgNx6#ETe%H5rg`X>loWg0amVId)oXP*w`+P9RbXRb9hId_X+X0 zD-mb`Cu=d_^&Xw<;ulj>r=AFam*hb`yTME{m%@?ibaHed2*BN$qlRJ}u+y?zUiSli zvcQ6o)zu)6z|2MTETl23(7evs#_&<@UP@CKZj)LJaQH z!X(Zp7jgi`RM@K=J$Jh@;KT4m`z}@=$8J7VN0#@068{`@ynj zngY{R2m(U0&QUWPQJig*dd>Tg>Tp^pMi~%Hu|1|ii*!q?tZbPBcUy~#6kddgfCJOM z7)cx=Lx+38czg*(#DIML+?8?9=mB2@!ZVz+4}++@AA)Sk0ewG=pOU{g9Hptl(e*>O zrcE(yj`CUf2!uF?dPt{io_6F;ryc;F70{^UH%l!Pc3?7%N}-7xOIZyDVkp(aLi^J3+iD?W63+cvl3SwHv=-M!C6%pDd_NzLCmoRB@Tpxa*@?Y#F_gS z7{p`Vp8?IXc>8Z-lOAJcQ`3Nnw3--7d|@jmo>^~CaHV0(xoH{!Xna zq35XfKAagtTHpbDid%~iCV*lTwp48vIv|iVh&KKjIT$MPq^@JAD3s_1IMKW6pZO# z0u4%{>VSLArGpE=O0+U&5Zxq$yF9*60}6qhHYD*-y>heXn0<+<87a}{*x*vcT_65) z)wAy_;c|Vsy3332@vSV7K#d(%xQf(5?2YZwp z?fUrChi6qO!3G{6zUV&E4Bu;)kURM2EJrqup{<(hJ~&0oREdj$DVtKtco^&SOT#d; zXc25@1K5OylyYT1qhZMKwt~}ycL6UU)-&h3triS66Cb0k6Tw0R2x@gh!)=qdL}6m>d0MNJf{}zfA9dlizceAsNXuQz(3hjE zX5BmD%i{y2B~6VO%=VHjn7Ux;IhG>3rv%0iTWX||{4zUR&5BdS`_(m$)@IVMBvL%_ z@PMT}GuEv9@-IGlE3XY6ORTuOkwHAM24-}?vKp3{4=cNsz5k?J`qA=14uUZ^^(z*J z;dg$Hm4JeDG${83Gp)tss9MCLiECa3u_xqn9hjQ_`gx%I~C_n$XbL(jC3t!_`u|B=oAA_?H; zLjTq6Y2bihbcc_lWtbOftsHP}xwOilXUzWQyEPKi3k8V%dJd@FnS&dIWGw`oUYd>5 zq~>h3Qf;-uqO>Ar+hki}e}jNFpDh2XNB86!)YYTR*>A4e9CFEQ)%WU_W+zjQUwG6T7Zj2mt$Y6A3vjO?QkY5(%4;Y-F#CQ{IFG?; zxQyZ}NC897PQ-3TOg>ttD=iwt_L@GXV+yViz2`boAgB6uQg_pL_x?4n_AbHl;eohI zZ`dbG?6?>fOJDcViEs`ejj0Q}UTqfz@>AQgdt;f^p55)=c7 zX`ZhNQ0c>=4vM5@P;4Bib-I8YcEk&<5maw4O;FC2Iy_C3f(s2&wrekGvxE zi7hC5UlKgA%nJxQNw2$Cm#E%c|_Zrv$dyt z89k`@GXAV8PIlZ}JNyb=13uS9Q&DMz;gx?gvDwx`$-+_{0}2R)GpOC5(mjPIg*hhOm)Omy-18gjaB&juZLMnFrV$Ly&zNRliVVfaKv zcob@f(9GEQu`*^KJ3`nNFA9ttqr2SE1tl@G^@14uu}(6qG+a_O%1>Esu(2qdBGh$Z zxN!NM>_(kPQ&?gP^^3dNIWaOod8^!y%&gwybP7>nAPYxd$)7LC#Uumw;!{ia<*ftm z;Mc=f(9^Y&(@0zG8PUf;IX(BZx2fv!%D0cYiqHI0fOu{EpEwBD8@pmb{lO%@b2v(B3x#LG9%7Mel>pKr~bxzd*X`FmF$ z8s)0)e}FZf_!B;jh}G-fb{z@;0_E4vwMMVFLDy}+zRwza{COXMm9Sry)E0(HJDBSS z-`P153Y5U^R2GySmH_3L;u=L&EA!~0O@9`9EsI-X=299V$rFas5N>!xjMr6BznZUV zh47fJ*GpK2nSM?;C%@3v?}1S|2t^V z%Z4k4YhH+Xi%M4ag0d45li${bNtC2{i`7HfMuz|)5GB~GA_Z2> zKOfUf;-OK2sgKEOnBh0flbBgyb8Ryj46o1M{Od6pHa|;X+u@cpDYX|vB;c4a!;AYF z)?H=i4a+(qPzd6S2U0x#7TAxr6 z3e3MQ1^JkVX2RXQM4rextiky!2wMT<7Pj1_mGV-3O$a-FD9fAPZ-O(W-$N}5VbH@p z58TQ~DODIWYidnoE{o}|DfPSPiGzMz3Fy@sy@7%4u*2ZAao;qPJZ;=~Nyp4T8=F%} zZg0BD#ygw3gUKu*InMrVe5@ngYMVHMnS!1jQ9K%-0r8PMFfB$FZ<`+Sk>6^ddttpR z`LT^HM|cB_+)9I8H*7lWsXn(kMLYg=D|!pns1#7EB{4mp+}=qie{%7LZNnf;%`@n+ zU$Mc1i$`Xhrh1*^?K~tbesTJ*fH7V6$n91GWnE67_<>GHtq3F^9`DcML#ysSxU}P; zA^!@*yb~gS>BGq>RGv(k;a-ogp6|&GmO>D6M?6ZGrdx1Fu9@Z+dj_mpz~}z?%q^U_ zx4?`DpjKLb{z=ypyp)yB@Ae#_Xv;Nae9$ZgHA!f38tb7Ej%;C_YeR-#Igh!&KjRl` zM(CGtm*DS@sF>-#Rhqs)a;V%YYVF2ol!1_tgdwFrQ~9sWBP5KFAVmFAdCXool=XTX zL-vJSML^TkO!1zZ-b=FBv=1gSYoSikA+V;vcwL=7CU(NC$LlB$CSyX(**?L`4Tt_X z0|b{`{ag`v~vHwH18$gGVi|J z&mOAzlZ^-GfZyXD;A65ivKskyY$@@QNrvKH(s*Wa2i9}Zay}S?Sxg3k@!@q9WnnL%W-i2y!$?Cs? zsN>zlL9~hdp>X^a-9aPyxPR3EwcO{!Lw>dEC+jcX9_VElwc* zaPDL%)HROt_2b!-vU|MwuXe`YDAKU63=M4A2d|VbuKH1LJ=UlGDx~Ak^T>H=xc9zI z9m-sG`4u}YmhVLB(5e{HI=gC>DmmO|nJQ@+4{rSRNp_eHibM%8GpG{KR`X(t)MzcE zU9;zmTSu>00U>SYFqEk)AEl@oK}eX+vffy$jNEl__JKTHo>YuSEiYss=&B)MVe3e9Fb6hQNsKIc{x(+utCIGFS(wi00GMZCWTqVu1 zDRTRb-H#rsVnN4cr3@QG2H^_ig{aG2C;|^68z_Jx>_ua<0L1i^AAqnD@}$&Q2Qaj} zSR-G+N5_emlV^A z!iAp zN~naDN(exD@i3(Le6U)R1Wt_$ax4M?vUfn-Ea5(`QG>U`+5BSgzd3i zuj_d|ujh3g?-8HG&=?YojqTJaj*Huox)5zX(|R(!bt_djUfH&Ugu5gP!&AP!fxpK0 zGND1AkO+a4aqj(FD8-n&cVEhmR1SE#4*oMLtnE1cwN-d>*J@Chg$V4KfB9_}mbF+! z@>E;V;6+di-PZgaFbgxTL|GeA_4|QYDV0TEf$)oEKBQUXNdj)CrdC=nq*OMEiEE6g zG+@&8TQ@=Hn01)sfsHM|8huKk#-dTS4S=yAc6*epSZDqolojonu1+0D628PZnmsl6 z?u#}N?mI~;}&Eu5n( z3q0L?`&h)O+@!kOs|!vDyK{F9Y)$f~#^3PM@A@K+I-2y{E$xE)#%PM$Yw+~?Wdr)a zj`WWOI~f3=6t5>6AXHsXujZ_Ac`VX=c#0}o<++2q$ZlVNo;LwZ&9)8^vlzL!^ej zB9KHo6o^SG%8EzUH&_Oj+o;Vp$tGipjnMP|TmxvI0TE8z~>hR5jN>gBLkZ zXM;74^~oGuLWV+&GJ@qI06A(q5fkwuM&4!+&!&*v`3ez1`QCG)qx*8|;w2*q2WBjs z=X~T{2S`zZAklMDq;D9l@Wt5Zw;@cl+j};2+{6RJ?%uOgsYCV@bVIaJIU8far`2#R zQsrV2Em+`tWq}#2Y(7Ixof)=(%VMKgiZ(XYW~;*Y{8AqcfW)@4KAgR6b$dgI^HpNx zlDj9Evrc;vDIx$zVN0u#4(qAy5Vc^&HPA=_Kn4+tF0!>;2;yfpDiV_Tz253$j_DZS zx1i<9E;1uupdy9u474+j*!Uw0D2X`!<)KpxvuW`x^`mjN>Bi~OM)vMi+A4Cp@tOuM zo2aSh?bwz&CpaN(Fcb-O1(dw-d`B7QTN6Kf2J1=(iV@H*uf-MMhNga=`LS2g9&koHM+YjseZy3(e&2NK(TKmKbX;3a7lW zNeM9sniC#lLNM;>eb2Tuv7};d&k{&ifJ;V)EDM~o=LR^y!YDw0atW2Omw)I(pb)r4 z7b5>${6wo2%)jNSL{0|vXK=zA__qtJJQGE0Az>EOUN4#FP{@g$qXMH|Vge@>f$z`i zH8P=DR0a~Aq$lpm9}}))#IOaez%3epo*k}WtL9fAEjpF%5!fPpHeViQG=`exe&cg_ zKR3HllvYlakR=hkoD6z;p%zY>MtdcK7_{!FCCXrNpNt9Q6?)N49~eQLQ~=M#jiDpEX6-sGU2vJqE4dyQi>|i}UiYy?5f^)7 z{FzEnHEjLc+#?aWb^7?mk7Y*2HqJPSNX=hUj$`9O*6p{E^}8|W46QVr*^0 zSmYUzs7YW$|DSvipZ|un^nYRP|A>R0a)2j>|K6!Q?8)@|az}mWaiY$GVLp1&dyVwOm^!%_<;$UN~{hkSpwR$9?*&1U>}! zW;kI1K=_P*mCVQkK4!JAx$eN&nWnk-2~aaVR?!7j?I<&XV2hM^WXoG9{AL0W*eZc3 zHu_nORK;n46nA}PitLE>7{NITDHnAMH)dlc5{2S}YNg8Dh(Emuwu+gMre;LFwr5(6 z;f4|Pig(q?`N-j%YE9+cgxy)3R_Y%1MrWxmN8?4WL0EH{NRI1Jc#jUon5FRLPs#yq zZipayz1u~45iTOWOE<<_bN4>T467Hhh2NQXb27G0E?bYzP;eqGCLnMXEhEB&bbEj5 zy?3$M&)eKnt>@p!^k?7upuSI@dt$6+;fhw~9`^A7HMq+yy2bji22)=7fIr^4O-c)Hc@=w5>udQL;5^m6d}=1mYc-`Q5}>?mtyMS{PFG7#tJ* ze%UPOY^bHz)|QiiixEpXP?B?fW(a+KefywMqo5yeyy_=t>RZ4qkNQLt~ zAe_Q6g{+b*x|f{WQD6KXy`cmR%oP9==htHaME%5+JS=F}id)DHL4q^7EAl9(hj&ok zow9I$z@`p3wu#$dY>>0b_Mg)Ld-SPo_}hi2?vIEr8J^QTi^LegjzR7M=ndzfcTZDD zRr{3KuhL*7eevzE=HcT=wn@=p8&~gJqnYi}#Dz`x+3dGFE-AVOJ(jo#Y7(1RT=3A) z!C@SwBSF32iL~+7TUqH8i0S*JegPlancAa=ii|YSS61|O>zm5dmBB%}rDMVV#Um1E z7zMLq=6>dv63+M@m+}WkI z1wR$o**S8*a0>WGsO@eHSN4S*rjSU*q-cIWvN@gxd(}e(dm)i&e^HX;!f+UkSZ~Ge z-rI52`QqIE^asRebCLYLh#!Pn?n*oA`}`v)lAKI%0ru~6$IP0ku3ZBPvMe3itZ#oL zv4wK+seGmE_;&=YIl@=gp-4N<0QB#T_U-L?g|JYpHh&jUWeKonZDj`DQZGT=kO>P7 zV_=KVGJcMkGH+GV7}reg8?dqmozWKO4=JR+f595@h`oQnU|4b7HjnRzR)?=0TzdXv zS;RSl^VQAGZS{%eNe(b2WxxDjL~q4KXDn-|{hH9E9&OT+6O_MJ9#v<%%Yj7c&#O$9|rL%UoEhVNxY zM`Bg_WMJ}5On0`82Rf>)t@h>WE2&JRQNig?g?ZFcW+qW086T?G5A)d(@p=uVDCX@- zxnhH+sKu#OP1=blGq8Mi@ZqnT^G$WpC`+r7N0yo(Mveas(}GqznuZ zzA*q07}g|A())`R(M!i5zaP7@v-Z8*ZwDhVKQ%B(U)hQ{X!uzas*iVI?e(93hc`*99Awqz{<~K(y2KWNY8Tr%VGRVC}Aj5lB3shJ$A&jJ=iLL7t zknz)DAU_F82sUcbOq^1CA5#(RiM(B3T&_S19Y_zaMxe3{unzHrA#(S;e&WkAA)I<$3N2&NDKt<}7H`3P5HP z+Q>`0dIhH|dN}TgUw-O^;FXZ_@X>KC%X|S&AcSS?!FFW@J6SOQ+(+f zVK?OAqtuSb5U`PO?Xr}!A`C7<5NDhgxdbN{8ZR4|Sq2~;#GDwzQV+jc8HOWKwvUv~ zdv~N5*F~^YZkp%XRBEj4JL?4(U<634>Dah|9GQKbiW|r>g&~V?sMT!u^JC5MtGlJ# zfCPc1IYO^=(J1?^&Y4>>3-Klk#F!ItQP>@Q{coExKQGSb$zBzsLVHDc)*^&00HQ2< z7GR3Z4^bqRM_Lo<=u*oREG)+31^YKV3+Op0YfO z1*Fz|QTlbM0O6ocw*I*~55I@rGv2BIZGCF_m3F#L!My-A|0Y85&A4GC!7-}(DRoJm z^h;#@tYt$t5aW~kFN|m%)va~#x>o3B1`1f7WW6op71dz8s8IW14G~_vKfY(nQLYw# zX32bR9T&4RwH}6T298{>FRo~*x1BREuyBViBmH~5z5hU|ja=9I_}c*cMFW51U2Fc4 zpryw8yr>s>kyQK=p@tH9f@c?;QZUoBWH3gTnd3y|*vwNgYuo$xoLWDSOylr(SeM?&~)v9sd4WX|BY35PQ zd7NQmwdg8sPM$$%WXy9#D(mqQuk)W@AEncRHayzVZJ@SXoA*V)Mu?tldP@v$4g301 z+e+|r<-TO!n`FkdN_UsKZe8fwDP(^X>adAaZ4)-V_bFZU0rG znxC7o%y9Qz<|Ww}Y2Q7iDE*7WB%2VaO~wgW#H~M|>(MH-1dwW>gqt=}8o9WmcTcYr zU}~3jo%$m@wz2vQJ6(@V@6I;xK=`KZUeR_yKO$rl#{O7QYK|bXQV<23jBV8@D@CXU z`3sKTjWeQN9g{-Q;;SfA5ycQOr)Ca7wZ1q>C4u6`8irQ4LJ)bKTUUZP3PBhWj}qoEm3UQ$P})nCzHraHH*UfI)wU@_7H_9lqEc zzD8C0<=j|vIE62tIDNKREisQT6FcHF4NLMPyQqVKU3zsS@0|>E+qhIBxGa574%Q1b$ht6$6Um+EQEU^MS@$f z`@C{F{`%ABCqaAdTEaGU$HtQ`O~Q7bhpGE<9?_F7Wn6Kw6G3zHwW$_oZ)$Y$CY9du zBMZ}85hyZ!S`mF8FoGep<;6>&#P$Y@gS=0jI=TcNr67>HpvAXV>l%6%;?=n&5K+%F z8MuEm*S#A<;O2E}B|(%5ZKz4eq?!p&yz3GhFpz1A@cN7i6LAN%rUW$B586&Qa+y~Y>0`tuG z6)(T4073Z!>+FlG4hIj>F>z0*dLNCmNBQpWy1U|&Dagqj8)@*vxn)IY1%NXB zOuK-Az^ISKmg)6N#v1jxE8WmPyW&=GjA>Pqz5Co=>&4I<1`j$53W}3#IOIvBR9G9l z^j~K7cNq~%>+RbP09u>M|F(kSos(B{h}oDjY%0+9cj1L&Tq8BMNE=L@YnH=84&<8J z(me;-U$9GDW`Ip>dc%!AGnj7D9UWw^UxZ#=aO%Z?-x=e1m?_hA>vc8~=UY-IKj;bClFR(h}yFDBb(rQN>0i zX?rPV+<3~L$L|c)a)(q(iNq{d!%ke8u6Y3Cdcu|4w{9J+jYs{GBP0v-L!;Om^O=4$ zG>r@7nm09CQD{@)6aau)c_52fN0T4drDd()GaYX ztw0>+2;SfALU}==_%i6y_XfrS=eCFZ^Nh_UMo3*+Bzx_fvutQV|94w9#hxXqjcC`1 zNGlRjU%}F!BYgHZQfUKbHcJ2;UUFV|l?>Ika_|XiA<($QkXct*HOVJ3ItBYu{kwyXJy1?w;@;-WOL zGc)uSNr4w3^xwovLH10$d9EZ-6e!3sx>3|?*zR3BRGebs4YzjhnNk5b85}Q#wv@QVH&=MRV1YdN}C2Ak+XUj!J^AuM z95Wpmxsp@09cjUOYs>f<@OBz1o-b>pEQ1{CIA6AB>2~JZSdQSx+k`gag}=M?<1HGgYt||d1|=ozeIhDb6u^vCMm;CSx9ceA`SR#H zq?O60v*MU2W@{FqdRrDSCgj=#=aLD@sI@p4&E&Hkm$A5c!9*}*iwVL)m?cUHrdM+V z?Qz9=^l&YAmY0Lugc6_mI#zM^h)bDUvz&qfthq_(`+cfzaO^Fb-Vf_#$^-mxFlepp zx`t1iZjoq|1YN#uBVHrIrz!pCC=1W*19LD{C`l)kb(gxMunG`8%O&~w8m3|yS=_0)tSRusZb+AoH!xAi6#8!g0i>OVd1&kP}z2P%vXS4`$uf^(wtuXBP zMh_;>6RYQ8g|-$H1H4}W=*HE{uC+5yp#xxp$8zfY#+V~>*98V*!Xl;9eQ^Ygt1?VK zjPd?9%kg(+KQer(#Fi-~tid9`Y(rz_WOSX4?R~q*h$#n%OBV!Ci+5Fdm+mr$;-c8K z{1!#o8e4z5m)CFUC{<0Hbg7$ar~W4ncjwRJc`-;c{WnV? z5@Z{I0Wzo`Y(1^pjRSUBUcX&(y+VZ_LS(s4=nZ$oDa~B^Gksf1u8+p4XtO5+e)`60 z*Jbv;p`_EBWA2Y@*03+*3ST`F4kan(OK~o% zVP$L&M88yUPI<#c@A>zZDYs?z?GZw``7>dpv!VKZdPqi@+0F) zvA~aP+pSci2=>(-w%9zYk}OMXO!u09U(UtQ52*xVf`HLfyC3z+qyrb>5~k5+Sw%|58_L2MdjOGwy3& z&X?*2qnPVb?~iu3_bolS@?n!lebxy*opHd)tvkFuajisCwGBUb#`;O|F8p04?flkH zu@Lox_OmuExWb;yN8hoIa_a zC9s{gfiEzbS1;w7pl}FgNJzu?$1slnx}kJth8ie;+omOi`n{n7!`O@30b_wo5mqH_ zxOV_HxY%UB&%_9}0~QGA_3U6;oPS70OQ_t}O8?E;l2xR*zPh}yfNr4B8@6Px$4}WU zI!T@$apWDkbDz1M9n5xYa>!^^9)=$7ms|QzrS{Mv27R1+=FWWtkvgUvrD1hD-qy|N zPqwL9;Edqx0MAiu1@k&#N*d(xwh7~^{c0&pt19*BjhEqUXtCNso0(u-RC)#3);a;d zX^51PsVsr=@U8bS^^%jOwHy527bG~OUBRfAqZYh%K@gWG_3N?DQaNz#n7Qqof|%a+km|`8r?2=gPMqB!XH+RHTa7*I%=Av8AXZ*+}@Z#hRj@;b`JVh{Ggo40a3Pr!SnSn!c&LlUKij-)w{O#-q#Rt}f zl+(R@`jMSKipkT#8hmhYUii|@K-Dv@9buMPv^|Sg6fQc$!fMSyn2mz3OTOD02 zm{2r2MZ3w;8b4Z`iKzA3fY`uM=9wLA31sv-Y+5vYY-PJ5h~boUGSEl9^!qyAxi6P; z$hW zie90Ea_8qT@wc#-7q{jhb}sRK+|dJHJpO?iRXKOeB5RDy-*^L2rFl@11lwA_boKKV z-S7L-sSnhicj39w&9c+)S=9tI!$y)y(f_$1gR~c9Y5(5^nU%8!NyrkXL2lpviJQ5O zja!{x@Q*lFVy*Mn1(^-U+(loN|5s_(0sE6$_5Tw+|Df^eamcY443$Is)>rZ6~ z4)57%rNk=5#XZ(T(GYA5WL@>2`$NV`R$V<+<}|Cnb!%e;0^}^a>8j`EcMk2VQENCJ z@sMD}vKF}j*st%jGP!YsX&34d{s^-aaq)Ye4lW7lnOvL9zhqQI35M@*KmGpO;Rn+R z?5-Vso{aAlcgp9RY}AwICk3v&i|Y*Zu7A4zu`EmH`^N&cC>0f~Ve|bo@hTYT^X~2l|n~CE3o`+g0L+6e!3v>?WOFo((rceROyCgF@+mLUmvN^sf9EIx6b6! z9LRk8P(@OvmpJI7HWrkOJH6KKz-;wMG{MPBJX|BP!hu-R9sxp+2pB*imeD-6V%0VP zBGR}Tn9Qk9Fx^b-z;Q69f~YKH1eOiw&A3w!?lfU@^bqE8)5&bq;Xjoepz-B-hY)*8 z2RdN2bOgmYZxFPffKw|Gd$VjjQ8_G;$7Grsi5N?F~EDMfNRK9}E98 zht?7>j{=E0@a}XZW?$uncYGrue2X0B%8{ev)b%HWW=6pBE1@6Y5;Qu`-Iro7(AISs zI4gh@==9u5qW#i(4t|b+DnT2;Ld)ja-_y$=iFmp2&+p>bEkzhT8vPOIBY(f^e8f|oP?&`<;9muNCs$=v@+e=`sClLc1d5nw zikuLlfhcuE=X0dzHvo749CjNAln~4`BE$Sb^kqyjfew2k(zO z2}6_2^iE#cp+LjsPDY@UF~4-(^=D$vcVKSy2SomkI>@H|rd9FxT3)FJaEXj_jk?(X zL)EYMOI}1@HurGY=EHuL@`eJY>tR0&z~5V?6~~gU8GY*a?`Sbj+%~yP zdJRz;S254_W0BkpXKL+5@rt!6h&^X&g8`AOx@@Zh#CU$xDZQ}VkEI}0WxSx9YUwPN zFTgJ5GTqMouk+09zv+Gazx3XMNSA7m#yaty0{(x5vDk~PjOTj@ATCksJp0!J^Z3lRmJ`4R@J|?rOh2CMmQ0Fh_Y@h&h>!@HEUbaq``Iqx--QUjHlfuO= zxS%sheb|Is#c_)NDEiN)9Ja6RIiIjzjPW&Yf8Md}#=gioiKC*b35=$4)H!NeK_gDBh~n)$3f>-Q1{B_@dz?O0%v-+MokA zYz*gH7QA0jf?B|R)3JYoG&0VAI!HMcU_UBV-ip3U8()G-t~t8w)LJEId>O`yykAZumu14Mfu#@(`UdZ+Q4F8u<>3)c}bv+=Ie%JV~0vu2Dv_3zTnNs zbHIdlvom0Y$cE#5}__}@R0~-&-`?4WX*3YP|cHx+p*B-sUc}sL$xQOw2c>wzHRU=elgJ;d# zKy=cik?lj29W8A|yewJrfF^gJ(Bo6Vi2aDAj#85W<)q_k5ha6^Z8D%)LqYnA(=>>> zYyGI0M%CpJmd%duwUnh#I0qRfA7uOy{PN;&v<_BL4lbjPc9h@i7*#}Hx;BW|u$gxf z+vTuAnir#rkn0tt(0M+GOx#D2mb>#Yg4R$%VA~W zZwD}xS`EJN4gW8bD@MzYY6d_312yfqyC)ZvKkNXP9=qOded({|VN=$bWIHg;^sa+; z88CZ9|Mje~M_2T}khi*OeqVv+LAyH!wZ|){J&4wb=25E`c}7cH1Pp68kqO=Lw^Uc( zQwg)sR@Ne`A2vF-8W!_q&dP-K<*i$Ow@(@s?|tA9@Ux%vM~|exL~NbkRn(cFZ{Txi z39dV#z=V2dA8R}Vl{2zOzjgX@6a4P}drz7Aa%)M8+L2LnOryDXc607bruQ7gJyss^ zE3cl->p22vt+}_0D`T${ZI$qDk`RwqVN1D1rq&GkX!^OQ$<;AXt6^xC!KDvK!!qho zm8i&d@&VhgV{AxZBjZ-%aNL*jh0fSAIPl!Sm#i4~U5xO;nJ;Eb3BG7g^){y$cO)R{ z_=jOC;Y>mmoeT=cs{ykW|lqiYn8ZA1uyJDi0w=+`<6 ztV@%TWQU8>0)8O$Q_-ulI%A5v&`bK}?aAFF4F`<*I4}~A%27WvdARW{Og0Q=bs?WvCBs@H80+}SUtv>+2w>`bF@pXAdJ5r}5fAbBGyl+KH{O8D_o59n)z|e12(g{J} zv|I$D8y|FZVbLwXq_d{YHgA%bxe1w2#!NnU;cB$m=5g^ z9(9sP3Ou#op#u|{kN=Hy-mdt-3#R+r4T`00~O$BK#@BGMr^(-EW4dO2ypfYqjiZt*%Yq79c~{0vLpL z26x2eV8yCmL~9X4`4ZJDsbj;e?*0f7v8qey->~$kxt}eDlhe#UjA z>@S+i-eOu=XXfSBHP0&BC6mYuxt`VV8tZ0d>=U;b+tlyp?PiyhQO~p+C^oOMx(1J?R~0m~{*OyA2f z_y@4E1O5{UaEx^?~Ubyh(hxAvB88cz$y|wBvi<{O=OsJADTe%E8tPFMcFtMw&OPFyJ26AUNn30 zyZPauWrniF&vIo~{5z)i{PAP;CzD|GMj%KMyFst>DOz!OsFvI9W8;)0Y@3ZoNoTaJ zAT^r1_wY{NfTf#pLt0;0&;Ew{@lprDQudazdds-eDT1t(*u*)Zh6}OM9(ZF$tsH4Z ziC6hI7qCPtA#KqwXyeE9BNfn7dj&X8%zd28*tW;~P$J(nafbaQBO3FrKh$X9r3l@` zS^UYk5Z>6>Sb)McL9OTVOAsAzLK}G=u!7bzywRzY1qVComOkB<*)iqEMsdD~i&1Ou z4Oe))NYn$+Fx?l+>`;IK))a1H3RSnEoPbwrwLaT=C3Uw*H|}+#%tfTV!|Bkh<=W9w zx&C_=PEWn5t-pg`2I?k7shXi|`UnHUdEPrY^eY1aVoiG-l!?=tJK4O_sBd4K7fL@g%MJSUM{i!CW7c2Q}dB@56vy#@Po4kf+nbMm&-QktvIgaTC}^jX+e= zisAaDB=?Lj7mLF;GvnFdOi}me8Sj|k#mpt@6H(|6MO4xPTlY-P!v2L6A~X`x`?H}a zl6_f&&hpfHXkG&#bSCS5WrD9Y;-J-*u}8g@k<-l{4quZ(R4(;k%jQ^;wCGAz)92RHKA58lSn;~STvtx zpA*zVGM@VCmzAc$NNW+saF)36q97nrN`Mj+Mh`v@Sy2Ts1c654zmi$7BSnk|jI9vA zR_qqEkNJrdJ=<%gaU!tmF?S%)rnbGToJMy(9qWIkBfi|=HNj>3z2c~k!!w{xt8jb3 z;4}M$>iuMW0wt{w8exp&{tNd39nhpt@1jy`&PGha!3GFAdWrZ3*?1>TLn)yD7Q z-n}=Ud}B6~@)>Z3zg-@PXp3ES1^fywErI2lJk&2KGrTjnD{l|925z|;YsCvZ6&#cF zt&ZJeWtp>|>Rv3wqkfSU!Rak8a%rXy%mMb|$ZHk9D3cQbEjHvGpDAhds8lAo@^dCJ zK59@@U(O~@l?0w%cFiE_ZOs1rr*BCDS9PCxz&YdGQZz&RW8d(gtfINdE_%vzS-t>e z3OsT&N%x&0GD{_-M@ttW>{ZAg8v^Rz75l_K)cs)O(JpbG|sr-1Fv zn_GIen}&rB&y1Av{W9p(@IAUo%|-#-m$Lp4oxmH=s{1aZWei7iuvP z&I|3PE!{e!p-goBn7*S->FrC>vM0-pjpL7xSptT-^Q$YL=!fk3<8vp_MYg#<8GxK> zLuw=-U&$7iO9lOAtrOdbNH|ytBM6`;jC2!-vzRz$T0dk}Z_mNdSW3=bz)^v~vCZ0z z8UB@xJt)U7_8`U3bJ8mRm%XryVn5#4KaHM0+krz()w-67elbN|n49UbQu@9Pkqgn1 zG|gD0)BQV z_F8;nQ(7~0^xC-S^_=oBP7|ZJcry=j)!vxojxeJJOgkVEOk&B-IiIR~G;GIOx2>@U zq0=LLcY5?P_=>)9Y5ObtwIFbUWFCE?R99Gj>PYj&b*d~h|46zBnM$MDuRqyr$Hy~; zYIqB`U86+7`CiSsXSY^ZPcxj1KZ5#m$GA2GqJVNT_tj040fKEZfLO;hP%5?a%Kg0T z76CSpFgHT6?82!NnjHKbB0DSQ%jajSmN_a|DmCvwHC}701N1y5E~(_doh-#(Pm5f| zRUdm$X9eJlUh9TAcS*n+#%HXMbMKU`U4YK(+&jMkHp&fyq>-NukYUzT1Ef2DY<>R* z^21$OkL!~~1*E!4PV%!2hm@Z7_ZeX(A-fGY>2o(0LO}^V(c5y?OOu8QwN1l+4n$5$ zt#NmyBDwDZbVO#l1lZsrbFE^DF1#mQid_~-|Jl0Z?S%ti(^h)p%0k5TIlp&oiXc82 zX8J~N;(z?rDeCV2@_0R%IS;3RGryOoiGcTSF5JwtpC+ zytB?KVhLFjFl6|`(}GtuPMpy&mb8p`*yyT}oN3>cSCl-W#~6~aJtfqlPk!`&RC(Y3 z#x>u6a7_mJdij$72iGdHmR1HDRvtX0DC79n)M|0SE-DKGu?i8%8XezwD2N0V=dX{-B-u~eh4k1DLXE@mH{4MZykYXv!t zEo=S8G)*?nccq?5hoqLl0<@kwq%ulgcWrH!TU`S4nM0GVTW=If=1jXon5 zT&%axfi)s+Cu|eiV19kyV#%6j)QzAu%7wVe!n=dBJ2EdJh`)z?*s!Ee;1jk4vwslc;5 zcqAFl0gMz~BnMs2eR}%!cFUQli}rC+;}IoTfJ;o~Of!5aVX)4XaUMbHyENUO#4N9j zBi!sv2`Te^GpQ`HaTFpLYgwIKrtmTrX^|fx3)#^M_a+>$63NBLeA?HLt*x>>xP$Z_ zZmQ2^>YrluJNb+^0Hmc{QhMv8I3FK_hk;F7zd&p*EwzFKkI31+_QOcbIZEV z%I4#JCV@@ucf11{2lfv)*}3>7Iypk&Yn$p1!QNa1ODn1G?Q7?VkgoO@oNXm4aD3Zq z?8hYZ@WNx*xgF}Y!8woyfjnsG*ZwkNEjd;kXVX3@B9AxBEvOjmP$CxD;6uC3KWAc{ zoWtG>`yREX4NK7I-sQgN&+pF@+FGVO2c~hBt?^G09st7jg!5po1pPD0o(oZ~$VwaM zMr>AHcDG`6p~1sd);4w%n#de1S1r!EG7-hweR9HR5N9&seDnxT)5>wQO;$|#?2%mv z0waZCj~TYakzAZx@ULKP`ha0>3c+(K5T|t(gz6u%S`%=_sPPwm`z>;;~PPmH?u!8prn1Jas}o5Vz=&-A=eKp30>2H0c6E7d4^SxqYn7w zSu&-V8K=J4tP5SArTUx;84jKr+|<>&^6qa=C$XqcOi}s|`^Mce^J*v(Z-XO*awCiT_rHc4QN3yR{xZd+wv94h2?6l0SSR~)>!`&v=;n-a7^o9-T&_} zYU@KeszFLH|M+n5Tez*_P@(iMA5Kez@Gqg>-=eXIE!7UAs|Twcw)jGj!KMTwRC zpth;)61^jlz0YrEY{30bB2tw$;-Ut>_^N(`eT6_P)H{W?FbHYD`j3ozxxnzs@xe34 zM@Vbz8bVAJSr0Cxt-2%IDNs^oZb1kKf<|W$FGKp(5p61t&^z0D%Z!gmS1B!j*>yf^ z4nP@D9R29Cp3O_>V}d&58&xm;Tiq5O>Z7D_-ac@35Wb-QF-1VtEPrP4=jri%kK3D| z%WfCbv+LT5u9Z_gIiH@M7ss+@{OZU>iRVO5Uwu?>2fcr^=m|ChfS!HD>Rsm-R{Ls9 zo~O+5@lv36jXAngjELV)zeH$Th(8=kozaTnh+E<*O1``EXw9xIUI1ggo{V`Ydl==Z z*;DI43B%F18A^dIZ5l*Qv4blkvi%*!2+0b(!|?O0=UY<6$IDj7P$Q?rg;P(3%IH{9 zKm^giMr2VuOrl1R7wY!GJf`5gC3HGIXBnC{LwgDtc#|hu;jUlQrR@k}bwT>$YD5Nd zgToMLzawDPx-Gvbi>Zd5N{&zl!mw?S5>vt1;y_UmGPn8rZgr{cg6pcScId|j*+?4+ zCQ}hjNe;<=%TT;$IibXwzG-><7IPXSfAN7_2DwHy1of7lu`*+om99uP3HzRli%QLl4rsW0*X_sJA9cZsx2{>JC`SvXDt3bZBn?wZmWjll-^V&cS`g!&C$L-X; zS7Z;6YuOgYSUqX9OT=2JL4RX!0rwWF7*n48s&mVG-^bmEqNRPuyC_D6hU{XVVHWWt z&tS`#iys?tYWC7at{Z%o8FgAd-2-5bFQ<-gna7F_V4riZf^)Wzb1Zc~YtGRrq`iwn z_ckoae&s(_wAcj7d0d5*oG-wDzS!T+F<5)B*|zRaaaV4#p=OC zE6Vf&*9xE1jbtR&a%21d3n&EF`@<9wDz0^Daf1+r2#UFIfe-5Ip!jYRyPixSFlFf6 zAm*ZpDF(5MX}O~Ml9-l)wWb1QNlF+w_XQuC5r~?YOB#-NAJ~D#2c3(8L^e@{x$L2H zNN^o)o+A_;WRQ;v!2?15(89n};DliLLIex)iA#Xu6NQ`$8$5T2z(g-JaSVzB0YJQz z2%&kMJA=gh#~M8`1pqUnNGLm%fH`vR4IMl{se$C2sr~RJEw*|;s!xQ`AJBS z;08Z%!2oFpgD*YDh9Kbv1l%Lb?VKkDK46iYNMIvf7=VV>C?PGj!3`bwA_hWq>IW6r zTVbqs|HIpmk1Tb_8~|7l0b1gv25AvOwNmniT>@YM>I_T(9B|6Em}sFX5yKNw_JSAe zU`d=}0D9H#_O z12$2mYhbwoqQ3A3ax%^dh+06nkP`$BL^Lo-sOU^`fGBC6MFH+}>dW4+(ZCoW2>*G( z2UL})E2zz5Gdjzo3gU!winR`KON#+a03sDofo_Q^zyu8H5*xHNKN(nMq|{(n+##Wk zqnetJP=J9BO4I>Hb;;nulOH9hE-+Ov0{kQb2{?2!Q3}A9xIU_|ICRVd2_smw6cC0e z|CFHzkbuM-kN^iau)(s3vVg5tpaPh7>Hu`GLZ|+Tl`bMAwgL?dUx&Mb8%W@)(RFT8 z_A(LzJYba{qV5V(paI}wR3Kn0X>?mOSP>L6Efo?kV`jhuwo2rrB+|hH+SQi>Jm8dD z2uw@m%a{^0U?Kr@k_TWArw2H|0S{;b1zI3t1*dc2&2WbR z65ttmDj@i*e@>MGYIQ_u=dDNv0z`G^K0De{x0Lb|zVpi&_)34X^66%ZgG|1f<* zQVXmsk^*Fw%`|ajq`XWYGMMQkD#o*G0`pTJ!8pr&dGlNbyr3QQqzQtK3J{>HfRg=( z1VJ%jq-pZSxd`_^R458$Ha!z81V%yWF+n(oLTZ`FXf7Gk0hHB_?jvGY;_SjH~<{4z|nm9L4^e^VgL}qrH4ig3p#e|VWZ%p@CksJ zBYok(ptxE;_)M!+2!JdL0N9bnGNKQ#<|k)B-iQ`R4xBt=C7dtc24Midozwvb#1-HO z$w9q0q=SDWTp~i4KoK?s0t$fp;Yzu{ouy|31{@sYAo)QAV8G+NWMBzfGWa;iO(FmU wJb(^BD7o7@V1pWLfdDIKN&pI=00ulD0#={^1ujql3QV8|4p0Cz7a9-%J3KwAM*si- literal 0 HcmV?d00001 diff --git a/commands/context/play.js b/commands/context/play.js new file mode 100644 index 0000000..58ddc3f --- /dev/null +++ b/commands/context/play.js @@ -0,0 +1,191 @@ +const { ContextMenuCommandBuilder } = require("@discordjs/builders"); +const { MessageEmbed } = require("discord.js"); +const escapeMarkdown = require('discord.js').Util.escapeMarkdown; + +module.exports = { + command: new ContextMenuCommandBuilder().setName("Play Song").setType(3), + + /** + * This function will handle context menu interaction + * @param {import("../lib/DiscordMusicBot")} client + * @param {import("discord.js").GuildContextMenuInteraction} interaction + */ + run: async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.createPlayer(interaction.channel, channel); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (player.state !== "CONNECTED") { + player.connect(); + } + + if (channel.type == "GUILD_STAGE_VOICE") { + setTimeout(() => { + if (interaction.guild.me.voice.suppress == true) { + try { + interaction.guild.me.voice.setSuppressed(false); + } catch (e) { + interaction.guild.me.voice.setRequestToSpeak(true); + } + } + }, 2000); // Need this because discord api is buggy asf, and without this the bot will not request to speak on a stage - Darren + } + + const ret = await interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(":mag_right: **Searching...**"), + ], + fetchReply: true, + }); + + const query = (interaction.channel.messages.cache.get(interaction.targetId).content ?? await interaction.channel.messages.fetch(interaction.targetId)); + let res = await player.search(query, interaction.user).catch((err) => { + client.error(err); + return { + loadType: "LOAD_FAILED", + }; + }); + + if (res.loadType === "LOAD_FAILED") { + if (!player.queue.current) { + player.destroy(); + } + await interaction + .editReply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There was an error while searching"), + ], + }) + .catch(this.warn); + } + + if (res.loadType === "NO_MATCHES") { + if (!player.queue.current) { + player.destroy(); + } + await interaction + .editReply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("No results were found"), + ], + }) + .catch(this.warn); + } + + if (res.loadType === "TRACK_LOADED" || res.loadType === "SEARCH_RESULT") { + player.queue.add(res.tracks[0]); + + if (!player.playing && !player.paused && !player.queue.size) { + player.play(); + } + var title = escapeMarkdown(res.tracks[0].title) + var title = title.replace(/\]/g, "") + var title = title.replace(/\[/g, "") + let addQueueEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setAuthor({ name: "Added to queue", iconURL: client.config.iconURL }) + .setDescription( + `[${title}](${res.tracks[0].uri})` || "No Title" + ) + .setURL(res.tracks[0].uri) + .addFields( + { + name: "Added by", + value: `<@${interaction.user.id}>`, + inline: true, + }, + { + name: "Duration", + value: res.tracks[0].isStream + ? `\`LIVE 🔴 \`` + : `\`${client.ms(res.tracks[0].duration, { + colonNotation: true, + secondsDecimalDigits: 0, + })}\``, + inline: true, + } + ); + + try { + addQueueEmbed.setThumbnail( + res.tracks[0].displayThumbnail("maxresdefault") + ); + } catch (err) { + addQueueEmbed.setThumbnail(res.tracks[0].thumbnail); + } + + if (player.queue.totalSize > 1) { + addQueueEmbed.addFields({ + name: "Position in queue", + value: `${player.queue.size}`, + inline: true, + }); + } else { + player.queue.previous = player.queue.current; + } + + await interaction.editReply({ embeds: [addQueueEmbed] }).catch(this.warn); + } + + if (res.loadType === "PLAYLIST_LOADED") { + player.queue.add(res.tracks); + + if ( + !player.playing && + !player.paused && + player.queue.totalSize === res.tracks.length + ) { + player.play(); + } + + let playlistEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setAuthor({ + name: "Playlist added to queue", + iconURL: client.config.iconURL, + }) + .setThumbnail(res.tracks[0].thumbnail) + .setDescription(`[${res.playlist.name}](${query})`) + .addFields( + { + name: "Enqueued", + value: `\`${res.tracks.length}\` songs`, + inline: true, + }, + { + name: "Playlist duration", + value: `\`${client.ms(res.playlist.duration, { + colonNotation: true, + secondsDecimalDigits: 0, + })}\``, + inline: true, + } + ); + + await interaction.editReply({ embeds: [playlistEmbed] }).catch(this.warn); + } + + if (ret) setTimeout(() => ret.delete().catch(this.warn), 20000); + return ret; + } +}; diff --git a/commands/slash/247.js b/commands/slash/247.js new file mode 100644 index 0000000..64c90a2 --- /dev/null +++ b/commands/slash/247.js @@ -0,0 +1,79 @@ +const colors = require("colors"); +const { MessageEmbed } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); + +const command = new SlashCommand() + .setName("247") + .setDescription("Prevents the bot from ever disconnecting from a VC (toggle)") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There's nothing to play 24/7."), + ], + ephemeral: true, + }); + } + + let twentyFourSevenEmbed = new MessageEmbed().setColor( + client.config.embedColor, + ); + const twentyFourSeven = player.get("twentyFourSeven"); + + if (!twentyFourSeven || twentyFourSeven === false) { + player.set("twentyFourSeven", true); + } else { + player.set("twentyFourSeven", false); + } + twentyFourSevenEmbed + .setDescription(`**24/7 mode is** \`${!twentyFourSeven ? "ON" : "OFF"}\``) + .setFooter({ + text: `The bot will ${!twentyFourSeven ? "now" : "no longer"} stay connected to the voice channel 24/7.` + }); + client.warn( + `Player: ${ player.options.guild } | [${ colors.blue( + "24/7", + ) }] has been [${ colors.blue( + !twentyFourSeven? "ENABLED" : "DISABLED", + ) }] in ${ + client.guilds.cache.get(player.options.guild) + ? client.guilds.cache.get(player.options.guild).name + : "a guild" + }`, + ); + + if (!player.playing && player.queue.totalSize === 0 && twentyFourSeven) { + player.destroy(); + } + + return interaction.reply({ embeds: [twentyFourSevenEmbed] }); + }); + +module.exports = command; +// check above message, it is a little bit confusing. and erros are not handled. probably should be fixed. +// ok use catch ez kom follow meh ;_; +// the above message meaning error, if it cant find it or take too long the bot crashed +// play commanddddd, if timeout or takes 1000 years to find song it crashed +// OKIE, leave the comment here for idk +// Comment very useful, 247 good :+1: +// twentyFourSeven = best; diff --git a/commands/slash/autoleave.js b/commands/slash/autoleave.js new file mode 100644 index 0000000..8b8d3d1 --- /dev/null +++ b/commands/slash/autoleave.js @@ -0,0 +1,62 @@ +const colors = require("colors"); +const { MessageEmbed } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); + +const command = new SlashCommand() + .setName("autoleave") + .setDescription("Automatically leaves when everyone leaves the voice channel (toggle)") + .setRun(async (client, interaction) => { + let channel = await client.getChannel(client, interaction); + if (!channel) return; + + let player; + if (client.manager) + player = client.manager.players.get(interaction.guild.id); + else + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There's nothing playing in the queue"), + ], + ephemeral: true, + }); + } + + let autoLeaveEmbed = new MessageEmbed().setColor(client.config.embedColor); + const autoLeave = player.get("autoLeave"); + player.set("requester", interaction.guild.me); + + if (!autoLeave || autoLeave === false) { + player.set("autoLeave", true); + } else { + player.set("autoLeave", false); + } + autoLeaveEmbed + .setDescription(`**Auto Leave is** \`${!autoLeave ? "ON" : "OFF"}\``) + .setFooter({ + text: `The player will ${!autoLeave ? "now automatically" : "not automatically"} leave when the voice channel is empty.` + }); + client.warn( + `Player: ${player.options.guild} | [${colors.blue( + "autoLeave" + )}] has been [${colors.blue(!autoLeave ? "ENABLED" : "DISABLED")}] in ${ + client.guilds.cache.get(player.options.guild) + ? client.guilds.cache.get(player.options.guild).name + : "a guild" + }` + ); + + return interaction.reply({ embeds: [autoLeaveEmbed] }); + }); + +module.exports = command; \ No newline at end of file diff --git a/commands/slash/autopause.js b/commands/slash/autopause.js new file mode 100644 index 0000000..1d9572a --- /dev/null +++ b/commands/slash/autopause.js @@ -0,0 +1,62 @@ +const colors = require("colors"); +const { MessageEmbed } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); + +const command = new SlashCommand() + .setName("autopause") + .setDescription("Automatically pause when everyone leaves the voice channel (toggle)") + .setRun(async (client, interaction) => { + let channel = await client.getChannel(client, interaction); + if (!channel) return; + + let player; + if (client.manager) + player = client.manager.players.get(interaction.guild.id); + else + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There's nothing playing in the queue"), + ], + ephemeral: true, + }); + } + + let autoPauseEmbed = new MessageEmbed().setColor(client.config.embedColor); + const autoPause = player.get("autoPause"); + player.set("requester", interaction.guild.me); + + if (!autoPause || autoPause === false) { + player.set("autoPause", true); + } else { + player.set("autoPause", false); + } + autoPauseEmbed + .setDescription(`**Auto Pause is** \`${!autoPause ? "ON" : "OFF"}\``) + .setFooter({ + text: `The player will ${!autoPause ? "now be automatically" : "no longer be"} paused when everyone leaves the voice channel.` + }); + client.warn( + `Player: ${player.options.guild} | [${colors.blue( + "AUTOPAUSE" + )}] has been [${colors.blue(!autoPause ? "ENABLED" : "DISABLED")}] in ${ + client.guilds.cache.get(player.options.guild) + ? client.guilds.cache.get(player.options.guild).name + : "a guild" + }` + ); + + return interaction.reply({ embeds: [autoPauseEmbed] }); + }); + +module.exports = command; \ No newline at end of file diff --git a/commands/slash/autoqueue.js b/commands/slash/autoqueue.js new file mode 100644 index 0000000..333b413 --- /dev/null +++ b/commands/slash/autoqueue.js @@ -0,0 +1,65 @@ +const colors = require("colors"); +const { MessageEmbed } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); + +const command = new SlashCommand() + .setName("autoqueue") + .setDescription("Automatically add songs to the queue (toggle)") + .setRun(async (client, interaction) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There's nothing playing in the queue"), + ], + ephemeral: true, + }); + } + + let autoQueueEmbed = new MessageEmbed().setColor(client.config.embedColor); + const autoQueue = player.get("autoQueue"); + player.set("requester", interaction.guild.me); + + if (!autoQueue || autoQueue === false) { + player.set("autoQueue", true); + } else { + player.set("autoQueue", false); + } + autoQueueEmbed + .setDescription(`**Auto Queue is** \`${!autoQueue ? "ON" : "OFF"}\``) + .setFooter({ + text: `Related music will ${!autoQueue ? "now be automatically" : "no longer be"} added to the queue.` + }); + client.warn( + `Player: ${ player.options.guild } | [${ colors.blue( + "AUTOQUEUE", + ) }] has been [${ colors.blue(!autoQueue? "ENABLED" : "DISABLED") }] in ${ + client.guilds.cache.get(player.options.guild) + ? client.guilds.cache.get(player.options.guild).name + : "a guild" + }`, + ); + + return interaction.reply({ embeds: [autoQueueEmbed] }); + }); + +module.exports = command; diff --git a/commands/slash/clean.js b/commands/slash/clean.js new file mode 100644 index 0000000..c123205 --- /dev/null +++ b/commands/slash/clean.js @@ -0,0 +1,49 @@ +const SlashCommand = require("../../lib/SlashCommand"); + +const command = new SlashCommand() + .setName("clean") + .setDescription("Cleans the last 100 bot messages from channel.") + .addIntegerOption((option) => + option + .setName("number") + .setDescription("Number of messages to delete.") + .setMinValue(2).setMaxValue(100) + .setRequired(false), + ) + .setRun(async (client, interaction, options) => { + + await interaction.deferReply(); + let number = interaction.options.getInteger("number"); + number = number && number < 100? ++number : 100; + + + interaction.channel.messages.fetch({ + limit: number, + }).then((messages) => { + const botMessages = []; + messages.filter(m => m.author.id === client.user.id).forEach(msg => botMessages.push(msg)) + + botMessages.shift(); + interaction.channel.bulkDelete(botMessages, true) + .then(async deletedMessages => { + //Filtering out messages that did not get deleted. + messages = messages.filter(msg => { + !deletedMessages.some(deletedMsg => deletedMsg == msg); + }); + if (messages.size > 0) { + client.log(`Deleting [${ messages.size }] messages older than 14 days.`) + for (const msg of messages) { + await msg.delete(); + } + } + + await interaction.editReply({ embeds: [client.Embed(`:white_check_mark: | Deleted ${ botMessages.length } bot messages`)] }); + setTimeout(() => { + interaction.deleteReply(); + }, 5000); + }) + + }); + }) + +module.exports = command; diff --git a/commands/slash/clear.js b/commands/slash/clear.js new file mode 100644 index 0000000..4f2e002 --- /dev/null +++ b/commands/slash/clear.js @@ -0,0 +1,54 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("clear") + .setDescription("Clear all tracks from queue") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Nothing is playing right now."), + ], + ephemeral: true, + }); + } + + if (!player.queue || !player.queue.length || player.queue.length === 0) { + let cembed = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("❌ | **Invalid, Not enough track to be cleared.**"); + + return interaction.reply({ embeds: [cembed], ephemeral: true }); + } + + player.queue.clear(); + + let clearEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`✅ | **Cleared the queue!**`); + + return interaction.reply({ embeds: [clearEmbed] }); + }); + +module.exports = command; \ No newline at end of file diff --git a/commands/slash/filters.js b/commands/slash/filters.js new file mode 100644 index 0000000..73455b3 --- /dev/null +++ b/commands/slash/filters.js @@ -0,0 +1,102 @@ +const { MessageEmbed } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); + +const command = new SlashCommand() + .setName("filters") + .setDescription("add or remove filters") + .addStringOption((option) => + option + .setName("preset") + .setDescription("the preset to add") + .setRequired(true) + .addChoices( + { name: "Nightcore", value: "nightcore" }, + { name: "BassBoost", value: "bassboost" }, + { name: "Vaporwave", value: "vaporwave" }, + { name: "Pop", value: "pop" }, + { name: "Soft", value: "soft" }, + { name: "Treblebass", value: "treblebass" }, + { name: "Eight Dimension", value: "eightD" }, + { name: "Karaoke", value: "karaoke" }, + { name: "Vibrato", value: "vibrato" }, + { name: "Tremolo", value: "tremolo" }, + { name: "Reset", value: "off" }, + ), + ) + + .setRun(async (client, interaction, options) => { + const args = interaction.options.getString("preset"); + + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There's no music playing."), + ], + ephemeral: true, + }); + } + + // create a new embed + let filtersEmbed = new MessageEmbed().setColor(client.config.embedColor); + + if (args == "nightcore") { + filtersEmbed.setDescription("✅ | Nightcore filter is now active!"); + player.nightcore = true; + } else if (args == "bassboost") { + filtersEmbed.setDescription("✅ | BassBoost filter is now on!"); + player.bassboost = true; + } else if (args == "vaporwave") { + filtersEmbed.setDescription("✅ | Vaporwave filter is now on!"); + player.vaporwave = true; + } else if (args == "pop") { + filtersEmbed.setDescription("✅ | Pop filter is now on!"); + player.pop = true; + } else if (args == "soft") { + filtersEmbed.setDescription("✅ | Soft filter is now on!"); + player.soft = true; + } else if (args == "treblebass") { + filtersEmbed.setDescription("✅ | Treblebass filter is now on!"); + player.treblebass = true; + } else if (args == "eightD") { + filtersEmbed.setDescription("✅ | Eight Dimension filter is now on!"); + player.eightD = true; + } else if (args == "karaoke") { + filtersEmbed.setDescription("✅ | Karaoke filter is now on!"); + player.karaoke = true; + } else if (args == "vibrato") { + filtersEmbed.setDescription("✅ | Vibrato filter is now on!"); + player.vibrato = true; + } else if (args == "tremolo") { + filtersEmbed.setDescription("✅ | Tremolo filter is now on!"); + player.tremolo = true; + } else if (args == "off") { + filtersEmbed.setDescription("✅ | EQ has been cleared!"); + player.reset(); + } else { + filtersEmbed.setDescription("❌ | Invalid filter!"); + } + + return interaction.reply({ embeds: [filtersEmbed] }); + }); + +module.exports = command; diff --git a/commands/slash/guildleave.js b/commands/slash/guildleave.js new file mode 100644 index 0000000..beab40f --- /dev/null +++ b/commands/slash/guildleave.js @@ -0,0 +1,56 @@ +const { MessageEmbed, message } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); +const fs = require("fs"); +const path = require("path"); +const { forEach } = require("lodash"); + +const command = new SlashCommand() + .setName("guildleave") + .setDescription("leaves a guild") + .addStringOption((option) => + option + .setName("id") + .setDescription("Enter the guild id to leave (type `list` for guild ids)") + .setRequired(true) + ) + .setRun(async (client, interaction, options) => { + if (interaction.user.id === client.config.adminId) { + try{ + const id = interaction.options.getString('id'); + + if (id.toLowerCase() === 'list'){ + client.guilds.cache.forEach((guild) => { + console.log(`${guild.name} | ${guild.id}`); + }); + const guild = client.guilds.cache.map(guild => ` ${guild.name} | ${guild.id}`); + try{ + return interaction.reply({content:`Guilds:\n\`${guild}\``, ephemeral: true}); + }catch{ + return interaction.reply({content:`check console for list of guilds`, ephemeral: true}); + } + } + + const guild = client.guilds.cache.get(id); + + if(!guild){ + return interaction.reply({content: `\`${id}\` is not a valid guild id`, ephemeral:true}); + } + + await guild.leave().then(c => console.log(`left guild ${id}`)).catch((err) => {console.log(err)}); + return interaction.reply({content:`left guild \`${id}\``, ephemeral: true}); + }catch (error){ + console.log(`there was an error trying to leave guild ${id}`, error); + } + }else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("You are not authorized to use this command!"), + ], + ephemeral: true, + }); + } + }); + +module.exports = command; diff --git a/commands/slash/help.js b/commands/slash/help.js new file mode 100644 index 0000000..f2c8385 --- /dev/null +++ b/commands/slash/help.js @@ -0,0 +1,135 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { + Client, + Interaction, + MessageActionRow, + MessageButton, + MessageEmbed, +} = require("discord.js"); +const LoadCommands = require("../../util/loadCommands"); +const { filter } = require("lodash"); + +const command = new SlashCommand() + .setName("help") + .setDescription("Shows this list") + .setRun(async (client, interaction) => { + await interaction.deferReply().catch((_) => {}); + // map the commands name and description to the embed + const commands = await LoadCommands().then((cmds) => { + return [].concat(cmds.slash) /*.concat(cmds.context)*/; + }); + // from commands remove the ones that have "null" in the description + const filteredCommands = commands.filter( + (cmd) => cmd.description != "null" + ); + //console.log(filteredCommands); + const totalCmds = filteredCommands.length; + let maxPages = Math.ceil(totalCmds / client.config.helpCmdPerPage); + + // if git exists, then get commit hash + let gitHash = ""; + try { + gitHash = require("child_process") + .execSync("git rev-parse --short HEAD") + .toString() + .trim(); + } catch (e) { + // do nothing + gitHash = "unknown"; + } + + // default Page No. + let pageNo = 0; + + const helpEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setAuthor({ + name: `Commands of ${client.user.username}`, + iconURL: client.config.iconURL, + }) + .setTimestamp() + .setFooter({ text: `Page ${pageNo + 1} / ${maxPages}` }); + + // initial temporary array + var tempArray = filteredCommands.slice( + pageNo * client.config.helpCmdPerPage, + pageNo * client.config.helpCmdPerPage + client.config.helpCmdPerPage + ); + + tempArray.forEach((cmd) => { + helpEmbed.addFields({ name: cmd.name, value: cmd.description }); + }); + helpEmbed.addFields({ + name: "Credits", + value: + `Discord Music Bot Version: v${ + require("../../package.json").version + }; Build: ${gitHash}` + + "\n" + + `[✨ Support Server](${client.config.supportServer}) | [Issues](${client.config.Issues}) | [Source](https://github.com/BestGamersH/Music-bot) | [Invite Me](https://discord.com/oauth2/authorize?client_id=${client.config.clientId}&permissions=${client.config.permissions}&scope=bot%20applications.commands)`, + }); + + // Construction of the buttons for the embed + const getButtons = (pageNo) => { + return new MessageActionRow().addComponents( + new MessageButton() + .setCustomId("help_cmd_but_2_app") + .setEmoji("◀ī¸") + .setStyle("PRIMARY") + .setDisabled(pageNo == 0), + new MessageButton() + .setCustomId("help_cmd_but_1_app") + .setEmoji("â–ļī¸") + .setStyle("PRIMARY") + .setDisabled(pageNo == maxPages - 1) + ); + }; + + const tempMsg = await interaction.editReply({ + embeds: [helpEmbed], + components: [getButtons(pageNo)], + fetchReply: true, + }); + const collector = tempMsg.createMessageComponentCollector({ + time: 600000, + componentType: "BUTTON", + }); + + collector.on("collect", async (iter) => { + if (iter.customId === "help_cmd_but_1_app") { + pageNo++; + } else if (iter.customId === "help_cmd_but_2_app") { + pageNo--; + } + + helpEmbed.fields = []; + + var tempArray = filteredCommands.slice( + pageNo * client.config.helpCmdPerPage, + pageNo * client.config.helpCmdPerPage + client.config.helpCmdPerPage + ); + + tempArray.forEach((cmd) => { + //console.log(cmd); + helpEmbed + .addFields({ name: cmd.name, value: cmd.description }) + .setFooter({ text: `Page ${pageNo + 1} / ${maxPages}` }); + }); + helpEmbed.addFields({ + name: "Credits", + value: + `Discord Music Bot Version: v${ + require("../../package.json").version + }; Build: ${gitHash}` + + "\n" + + `[✨ Support Server](${client.config.supportServer}) | [Issues](${client.config.Issues}) | [Source](https://github.com/BestGamersH/Music-bot) | [Invite Me](https://discord.com/oauth2/authorize?client_id=${client.config.clientId}&permissions=${client.config.permissions}&scope=bot%20applications.commands)`, + }); + await iter.update({ + embeds: [helpEmbed], + components: [getButtons(pageNo)], + fetchReply: true, + }); + }); + }); + +module.exports = command; diff --git a/commands/slash/invite.js b/commands/slash/invite.js new file mode 100644 index 0000000..c6b402c --- /dev/null +++ b/commands/slash/invite.js @@ -0,0 +1,30 @@ +const { MessageActionRow, MessageButton, MessageEmbed } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); + +const command = new SlashCommand() + .setName("invite") + .setDescription("Invite me to your server") + .setRun(async (client, interaction, options) => { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setTitle(`Invite me to your server!`), + ], + components: [ + new MessageActionRow().addComponents( + new MessageButton() + .setLabel("Invite me") + .setStyle("LINK") + .setURL( + `https://discord.com/oauth2/authorize?client_id=${ + client.config.clientId + }&permissions=${ + client.config.permissions + }&scope=${ client.config.scopes.toString().replace(/,/g, "%20") }`, + ), + ), + ], + }); + }); +module.exports = command; diff --git a/commands/slash/loop.js b/commands/slash/loop.js new file mode 100644 index 0000000..84cf59e --- /dev/null +++ b/commands/slash/loop.js @@ -0,0 +1,51 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("loop") + .setDescription("Loops the current song") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Nothing is playing right now."), + ], + ephemeral: true, + }); + } + + if (player.setTrackRepeat(!player.trackRepeat)) { + ; + } + const trackRepeat = player.trackRepeat? "enabled" : "disabled"; + + interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`👍 | **Loop has been \`${ trackRepeat }\`**`), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/loopq.js b/commands/slash/loopq.js new file mode 100644 index 0000000..f90bf23 --- /dev/null +++ b/commands/slash/loopq.js @@ -0,0 +1,53 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("loopq") + .setDescription("Loop the current song queue") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There is no music playing."), + ], + ephemeral: true, + }); + } + + if (player.setQueueRepeat(!player.queueRepeat)) { + ; + } + const queueRepeat = player.queueRepeat? "enabled" : "disabled"; + + interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `:thumbsup: | **Loop queue is now \`${ queueRepeat }\`**`, + ), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/lyrics.js b/commands/slash/lyrics.js new file mode 100644 index 0000000..1c2d3fd --- /dev/null +++ b/commands/slash/lyrics.js @@ -0,0 +1,233 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { + MessageActionRow, + MessageSelectMenu, + MessageButton, + MessageEmbed +} = require("discord.js"); +const { Rlyrics } = require("rlyrics"); +const lyricsApi = new Rlyrics(); + +const command = new SlashCommand() + .setName("lyrics") + .setDescription("Get the lyrics of a song") + .addStringOption((option) => + option + .setName("song") + .setDescription("The song to get lyrics for") + .setRequired(false), + ) + .setRun(async (client, interaction, options) => { + await interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("🔎 | **Searching...**"), + ], + }); + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + const args = interaction.options.getString("song"); + if (!args && !player) { + return interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There's nothing playing"), + ], + }); + } + + let currentTitle = ``; + const phrasesToRemove = [ + "Full Video", "Full Audio", "Official Music Video", "Lyrics", "Lyrical Video", + "Feat.", "Ft.", "Official", "Audio", "Video", "HD", "4K", "Remix", + "Extended", "DJ Edit", "with Lyrics", "Lyrics", "Karaoke", + "Instrumental", "Live", "Acoustic", "Cover", "\\(feat\\. .*\\)" + ]; + if (!args) { + currentTitle = player.queue.current.title; + currentTitle = currentTitle + .replace(new RegExp(phrasesToRemove.join('|'), 'gi'), '') + .replace(/\s*([\[\(].*?[\]\)])?\s*(\|.*)?\s*(\*.*)?$/, ''); + } + let query = args ? args : currentTitle; + let lyricsResults = []; + + lyricsApi.search(query).then(async (lyricsData) => { + if (lyricsData.length !== 0) { + for (let i = 0; i < client.config.lyricsMaxResults; i++) { + if (lyricsData[i]) { + lyricsResults.push({ + label: `${lyricsData[i].title}`, + description: `${lyricsData[i].artist}`, + value: i.toString() + }); + } else { break } + } + + const menu = new MessageActionRow().addComponents( + new MessageSelectMenu() + .setCustomId("choose-lyrics") + .setPlaceholder("Choose a song") + .addOptions(lyricsResults), + ); + + let selectedLyrics = await interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `Here are some of the results I found for \`${query}\`. Please choose a song to display lyrics within \`30 seconds\`.` + ), + ], components: [menu], + }); + + const filter = (button) => button.user.id === interaction.user.id; + + const collector = selectedLyrics.createMessageComponentCollector({ + filter, + time: 30000, + }); + + collector.on("collect", async (interaction) => { + if (interaction.isSelectMenu()) { + await interaction.deferUpdate(); + const url = lyricsData[parseInt(interaction.values[0])].url; + + lyricsApi.find(url).then((lyrics) => { + let lyricsText = lyrics.lyrics; + + const button = new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId('tipsbutton') + .setLabel('Tips') + .setEmoji(`📌`) + .setStyle('SECONDARY'), + new MessageButton() + .setLabel('Source') + .setURL(url) + .setStyle('LINK'), + ); + + const musixmatch_icon = 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e3/Musixmatch_logo_icon_only.svg/480px-Musixmatch_logo_icon_only.svg.png'; + let lyricsEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setTitle(`${lyrics.name}`) + .setURL(url) + .setThumbnail(lyrics.icon) + .setFooter({ + text: 'Lyrics provided by MusixMatch.', + iconURL: musixmatch_icon + }) + .setDescription(lyricsText); + + if (lyricsText.length === 0) { + lyricsEmbed + .setDescription(`**Unfortunately we're not authorized to show these lyrics.**`) + .setFooter({ + text: 'Lyrics is restricted by MusixMatch.', + iconURL: musixmatch_icon + }) + } + + if (lyricsText.length > 4096) { + lyricsText = lyricsText.substring(0, 4050) + "\n\n[...]"; + lyricsEmbed + .setDescription(lyricsText + `\nTruncated, the lyrics were too long.`) + } + + return interaction.editReply({ + embeds: [lyricsEmbed], + components: [button], + }); + + }) + } + }); + + collector.on("end", async (i) => { + if (i.size == 0) { + selectedLyrics.edit({ + content: null, + embeds: [ + new MessageEmbed() + .setDescription( + `No song is selected. You took too long to select a track.` + ) + .setColor(client.config.embedColor), + ], components: [], + }); + } + }); + + } else { + const button = new MessageActionRow() + .addComponents( + new MessageButton() + .setEmoji(`📌`) + .setCustomId('tipsbutton') + .setLabel('Tips') + .setStyle('SECONDARY'), + ); + return interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription( + `No results found for \`${query}\`!\nMake sure you typed in your search correctly.`, + ), + ], components: [button], + }); + } + }).catch((err) => { + console.error(err); + return interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription( + `An unknown error has occured, please check your console.`, + ), + ], + }); + }); + + const collector = interaction.channel.createMessageComponentCollector({ + time: 1000 * 3600 + }); + + collector.on('collect', async interaction => { + if (interaction.customId === 'tipsbutton') { + await interaction.deferUpdate(); + await interaction.followUp({ + embeds: [ + new MessageEmbed() + .setTitle(`Lyrics Tips`) + .setColor(client.config.embedColor) + .setDescription( + `Here is some tips to get your song lyrics correctly \n\n\ + 1. Try to add the artist's name in front of the song name.\n\ + 2. Try to search the lyrics manually by providing the song query using your keyboard.\n\ + 3. Avoid searching lyrics in languages other than English.`, + ), + ], ephemeral: true, components: [] + }); + }; + }); + }); + +module.exports = command; diff --git a/commands/slash/move.js b/commands/slash/move.js new file mode 100644 index 0000000..33125d0 --- /dev/null +++ b/commands/slash/move.js @@ -0,0 +1,75 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("move") + .setDescription("Moves track to a different position") + .addIntegerOption((option) => + option + .setName("track") + .setDescription("The track number to move") + .setRequired(true), + ) + .addIntegerOption((option) => + option + .setName("position") + .setDescription("The position to move the track to") + .setRequired(true), + ) + + .setRun(async (client, interaction) => { + const track = interaction.options.getInteger("track"); + const position = interaction.options.getInteger("position"); + + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There's nothing playing."), + ], + ephemeral: true, + }); + } + + let trackNum = Number(track) - 1; + if (trackNum < 0 || trackNum > player.queue.length - 1) { + return interaction.reply(":x: | **Invalid track number**"); + } + + let dest = Number(position) - 1; + if (dest < 0 || dest > player.queue.length - 1) { + return interaction.reply(":x: | **Invalid position number**"); + } + + const thing = player.queue[trackNum]; + player.queue.splice(trackNum, 1); + player.queue.splice(dest, 0, thing); + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(":white_check_mark: | **Moved track**"), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/nowplaying.js b/commands/slash/nowplaying.js new file mode 100644 index 0000000..017d0a1 --- /dev/null +++ b/commands/slash/nowplaying.js @@ -0,0 +1,83 @@ +const { MessageEmbed } = require("discord.js"); +const escapeMarkdown = require('discord.js').Util.escapeMarkdown; +const SlashCommand = require("../../lib/SlashCommand"); +const prettyMilliseconds = require("pretty-ms"); + +const command = new SlashCommand() + .setName("nowplaying") + .setDescription("Shows the song currently playing in the voice channel.") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("The bot isn't in a channel."), + ], + ephemeral: true, + }); + } + + if (!player.playing) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There's nothing playing."), + ], + ephemeral: true, + }); + } + + const song = player.queue.current; + var title = escapeMarkdown(song.title) + var title = title.replace(/\]/g,"") + var title = title.replace(/\[/g,"") + const embed = new MessageEmbed() + .setColor(client.config.embedColor) + .setAuthor({ name: "Now Playing", iconURL: client.config.iconURL }) + // show who requested the song via setField, also show the duration of the song + .setFields([ + { + name: "Requested by", + value: `<@${ song.requester.id }>`, + inline: true, + }, + // show duration, if live show live + { + name: "Duration", + value: song.isStream + ? `\`LIVE\`` + : `\`${ prettyMilliseconds(player.position, { + secondsDecimalDigits: 0, + }) } / ${ prettyMilliseconds(song.duration, { + secondsDecimalDigits: 0, + }) }\``, + inline: true, + }, + ]) + // show the thumbnail of the song using displayThumbnail("maxresdefault") + .setThumbnail(song.displayThumbnail("maxresdefault")) + // show the title of the song and link to it + .setDescription(`[${ title }](${ song.uri })`); + return interaction.reply({ embeds: [embed] }); + }); +module.exports = command; diff --git a/commands/slash/pause.js b/commands/slash/pause.js new file mode 100644 index 0000000..d70121b --- /dev/null +++ b/commands/slash/pause.js @@ -0,0 +1,58 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("pause") + .setDescription("Pauses the current playing track") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Nothing is playing."), + ], + ephemeral: true, + }); + } + + if (player.paused) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Current playing track is already paused!"), + ], + ephemeral: true, + }); + } + + player.pause(true); + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`⏸ | **Paused!**`), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/ping.js b/commands/slash/ping.js new file mode 100644 index 0000000..ea9b7fc --- /dev/null +++ b/commands/slash/ping.js @@ -0,0 +1,69 @@ +const { MessageEmbed } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); + +const command = new SlashCommand() + .setName("ping") + .setDescription("View the bot's latency") + .setRun(async (client, interaction, options) => { + let msg = await interaction.channel.send({ + embeds: [ + new MessageEmbed() + .setDescription("🏓 | Fetching ping...") + .setColor("#6F8FAF"), + ], + }); + + let zap = "⚡"; + let green = "đŸŸĸ"; + let red = "🔴"; + let yellow = "🟡"; + + var botState = zap; + var apiState = zap; + + let apiPing = client.ws.ping; + let botPing = Math.floor(msg.createdAt - interaction.createdAt); + + if (apiPing >= 40 && apiPing < 200) { + apiState = green; + } else if (apiPing >= 200 && apiPing < 400) { + apiState = yellow; + } else if (apiPing >= 400) { + apiState = red; + } + + if (botPing >= 40 && botPing < 200) { + botState = green; + } else if (botPing >= 200 && botPing < 400) { + botState = yellow; + } else if (botPing >= 400) { + botState = red; + } + + msg.delete(); + interaction.reply({ + embeds: [ + new MessageEmbed() + .setTitle("🏓 | Pong!") + .addFields( + { + name: "API Latency", + value: `\`\`\`yml\n${apiState} | ${apiPing}ms\`\`\``, + inline: true, + }, + { + name: "Bot Latency", + value: `\`\`\`yml\n${botState} | ${botPing}ms\`\`\``, + inline: true, + } + ) + .setColor(client.config.embedColor) + .setFooter({ + text: `Requested by ${interaction.user.tag}`, + iconURL: interaction.user.avatarURL(), + }), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/play.js b/commands/slash/play.js new file mode 100644 index 0000000..95716ac --- /dev/null +++ b/commands/slash/play.js @@ -0,0 +1,196 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); +const escapeMarkdown = require('discord.js').Util.escapeMarkdown; + +const command = new SlashCommand() + .setName("play") + .setDescription( + "Searches and plays the requested song \nSupports: \nYoutube, Spotify, Deezer, Apple Music" + ) + .addStringOption((option) => + option + .setName("query") + .setDescription("What am I looking for?") + .setAutocomplete(true) + .setRequired(true) + ) + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.createPlayer(interaction.channel, channel); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (player.state !== "CONNECTED") { + player.connect(); + } + + if (channel.type == "GUILD_STAGE_VOICE") { + setTimeout(() => { + if (interaction.guild.me.voice.suppress == true) { + try { + interaction.guild.me.voice.setSuppressed(false); + } catch (e) { + interaction.guild.me.voice.setRequestToSpeak(true); + } + } + }, 2000); // Need this because discord api is buggy asf, and without this the bot will not request to speak on a stage - Darren + } + + const ret = await interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(":mag_right: **Searching...**"), + ], + fetchReply: true, + }); + + let query = options.getString("query", true); + let res = await player.search(query, interaction.user).catch((err) => { + client.error(err); + return { + loadType: "LOAD_FAILED", + }; + }); + + if (res.loadType === "LOAD_FAILED") { + if (!player.queue.current) { + player.destroy(); + } + await interaction + .editReply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There was an error while searching"), + ], + }) + .catch(this.warn); + } + + if (res.loadType === "NO_MATCHES") { + if (!player.queue.current) { + player.destroy(); + } + await interaction + .editReply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("No results were found"), + ], + }) + .catch(this.warn); + } + + if (res.loadType === "TRACK_LOADED" || res.loadType === "SEARCH_RESULT") { + player.queue.add(res.tracks[0]); + + if (!player.playing && !player.paused && !player.queue.size) { + player.play(); + } + var title = escapeMarkdown(res.tracks[0].title) + var title = title.replace(/\]/g,"") + var title = title.replace(/\[/g,"") + let addQueueEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setAuthor({ name: "Added to queue", iconURL: client.config.iconURL }) + .setDescription( + `[${title}](${res.tracks[0].uri})` || "No Title" + ) + .setURL(res.tracks[0].uri) + .addFields( + { + name: "Added by", + value: `<@${interaction.user.id}>`, + inline: true, + }, + { + name: "Duration", + value: res.tracks[0].isStream + ? `\`LIVE 🔴 \`` + : `\`${client.ms(res.tracks[0].duration, { + colonNotation: true, + secondsDecimalDigits: 0, + })}\``, + inline: true, + } + ); + + try { + addQueueEmbed.setThumbnail( + res.tracks[0].displayThumbnail("maxresdefault") + ); + } catch (err) { + addQueueEmbed.setThumbnail(res.tracks[0].thumbnail); + } + + if (player.queue.totalSize > 1) { + addQueueEmbed.addFields({ + name: "Position in queue", + value: `${player.queue.size}`, + inline: true, + }); + } else { + player.queue.previous = player.queue.current; + } + + await interaction.editReply({ embeds: [addQueueEmbed] }).catch(this.warn); + } + + if (res.loadType === "PLAYLIST_LOADED") { + player.queue.add(res.tracks); + + if ( + !player.playing && + !player.paused && + player.queue.totalSize === res.tracks.length + ) { + player.play(); + } + + let playlistEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setAuthor({ + name: "Playlist added to queue", + iconURL: client.config.iconURL, + }) + .setThumbnail(res.tracks[0].thumbnail) + .setDescription(`[${res.playlist.name}](${query})`) + .addFields( + { + name: "Enqueued", + value: `\`${res.tracks.length}\` songs`, + inline: true, + }, + { + name: "Playlist duration", + value: `\`${client.ms(res.playlist.duration, { + colonNotation: true, + secondsDecimalDigits: 0, + })}\``, + inline: true, + } + ); + + await interaction.editReply({ embeds: [playlistEmbed] }).catch(this.warn); + } + + if (ret) setTimeout(() => ret.delete().catch(this.warn), 20000); + return ret; + }); + +module.exports = command; diff --git a/commands/slash/previous.js b/commands/slash/previous.js new file mode 100644 index 0000000..7cb45da --- /dev/null +++ b/commands/slash/previous.js @@ -0,0 +1,67 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() +.setName("previous") +.setDescription("Go back to the previous song.") +.setRun(async (client, interaction) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There are no previous songs for this session."), + ], + ephemeral: true, + }); + } + + const previousSong = player.queue.previous; + const currentSong = player.queue.current; + const nextSong = player.queue[0] + + if (!previousSong + || previousSong === currentSong + || previousSong === nextSong) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There is no previous song in the queue."), + ], + })} + + if (previousSong !== currentSong && previousSong !== nextSong) { + player.queue.splice(0, 0, currentSong) + player.play(previousSong); + } + interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `⏎ | Previous song: **${ previousSong.title }**`, + ), + ], + }); +}); + +module.exports = command; diff --git a/commands/slash/queue.js b/commands/slash/queue.js new file mode 100644 index 0000000..0d21d3e --- /dev/null +++ b/commands/slash/queue.js @@ -0,0 +1,347 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed, MessageButton, MessageActionRow } = require("discord.js"); +const escapeMarkdown = require('discord.js').Util.escapeMarkdown; +const load = require("lodash"); +const pms = require("pretty-ms"); + +const command = new SlashCommand() + .setName("queue") + .setDescription("Shows the current queue") + + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There are no songs in the queue."), + ], + ephemeral: true, + }); + } + + if (!player.playing) { + const queueEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("There's nothing playing."); + return interaction.reply({ embeds: [queueEmbed], ephemeral: true }); + } + + await interaction.deferReply().catch(() => { + }); + + + if (!player.queue.size || player.queue.size === 0) { + let song = player.queue.current; + var title = escapeMarkdown(song.title) + var title = title.replace(/\]/g,"") + var title = title.replace(/\[/g,"") + const queueEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`**â™Ē | Now playing:** [${ title }](${ song.uri })`) + .addFields( + { + name: "Duration", + value: song.isStream + ? `\`LIVE\`` + : `\`${ pms(player.position, { colonNotation: true }) } / ${ pms( + player.queue.current.duration, + { colonNotation: true }, + ) }\``, + inline: true, + }, + { + name: "Volume", + value: `\`${ player.volume }\``, + inline: true, + }, + { + name: "Total Tracks", + value: `\`${ player.queue.totalSize - 1 }\``, + colonNotation: true, + inline: true, + }, + ); + + await interaction.editReply({ + embeds: [queueEmbed], + }); + } else { + let queueDuration = player.queue.duration.valueOf() + if (player.queue.current.isStream) { + queueDuration -= player.queue.current.duration + } + for (let i = 0; i < player.queue.length; i++) { + if (player.queue[i].isStream) { + queueDuration -= player.queue[i].duration + } + } + + const mapping = player.queue.map( + (t, i) => `\` ${ ++i } \` [${ t.title }](${ t.uri }) [${ t.requester }]`, + ); + + const chunk = load.chunk(mapping, 10); + const pages = chunk.map((s) => s.join("\n")); + let page = interaction.options.getNumber("page"); + if (!page) { + page = 0; + } + if (page) { + page = page - 1; + } + if (page > pages.length) { + page = 0; + } + if (page < 0) { + page = 0; + } + + if (player.queue.size < 11 || player.queue.totalSize < 11) { + let song = player.queue.current; + var title = escapeMarkdown(song.title) + var title = title.replace(/\]/g,"") + var title = title.replace(/\[/g,"") + const embedTwo = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `**â™Ē | Now playing:** [${ title }](${ song.uri }) [${ player.queue.current.requester }]\n\n**Queued Tracks**\n${ pages[page] }`, + ) + .addFields( + { + name: "Track Duration", + value: song.isStream + ? `\`LIVE\`` + : `\`${ pms(player.position, { colonNotation: true }) } / ${ pms( + player.queue.current.duration, + { colonNotation: true }, + ) }\``, + inline: true, + }, + { + name: "Total Tracks Duration", + value: `\`${ pms(queueDuration, { + colonNotation: true, + }) }\``, + inline: true, + }, + { + name: "Total Tracks", + value: `\`${ player.queue.totalSize - 1 }\``, + colonNotation: true, + inline: true, + }, + ) + .setFooter({ + text: `Page ${ page + 1 }/${ pages.length }`, + }); + + await interaction + .editReply({ + embeds: [embedTwo], + }) + .catch(() => { + }); + } else { + let song = player.queue.current; + var title = escapeMarkdown(song.title) + var title = title.replace(/\]/g,"") + var title = title.replace(/\[/g,"") + const embedThree = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `**â™Ē | Now playing:** [${ title }](${ song.uri }) [${ player.queue.current.requester }]\n\n**Queued Tracks**\n${ pages[page] }`, + ) + .addFields( + { + name: "Track Duration", + value: song.isStream + ? `\`LIVE\`` + : `\`${ pms(player.position, { colonNotation: true }) } / ${ pms( + player.queue.current.duration, + { colonNotation: true }, + ) }\``, + inline: true, + }, + { + name: "Total Tracks Duration", + value: `\`${ pms(queueDuration, { + colonNotation: true, + }) }\``, + inline: true, + }, + { + name: "Total Tracks", + value: `\`${ player.queue.totalSize - 1 }\``, + colonNotation: true, + inline: true, + }, + ) + .setFooter({ + text: `Page ${ page + 1 }/${ pages.length }`, + }); + + const buttonOne = new MessageButton() + .setCustomId("queue_cmd_but_1_app") + .setEmoji("⏭ī¸") + .setStyle("PRIMARY"); + const buttonTwo = new MessageButton() + .setCustomId("queue_cmd_but_2_app") + .setEmoji("⏎ī¸") + .setStyle("PRIMARY"); + + await interaction + .editReply({ + embeds: [embedThree], + components: [ + new MessageActionRow().addComponents([buttonTwo, buttonOne]), + ], + }) + .catch(() => { + }); + + const collector = interaction.channel.createMessageComponentCollector({ + filter: (b) => { + if (b.user.id === interaction.user.id) { + return true; + } else { + return b + .reply({ + content: `Only **${ interaction.user.tag }** can use this button.`, + ephemeral: true, + }) + .catch(() => { + }); + } + }, + time: 60000 * 5, + idle: 30e3, + }); + + collector.on("collect", async (button) => { + if (button.customId === "queue_cmd_but_1_app") { + await button.deferUpdate().catch(() => { + }); + page = page + 1 < pages.length? ++page : 0; + let song = player.queue.current; + var title = escapeMarkdown(song.title) + var title = title.replace(/\]/g,"") + var title = title.replace(/\[/g,"") + const embedFour = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `**â™Ē | Now playing:** [${ title }](${ song.uri }) [${ player.queue.current.requester }]\n\n**Queued Tracks**\n${ pages[page] }`, + ) + .addFields( + { + name: "Track Duration", + value: song.isStream + ? `\`LIVE\`` + : `\`${ pms(player.position, { colonNotation: true }) } / ${ pms( + player.queue.current.duration, + { colonNotation: true }, + ) }\``, + inline: true, + }, + { + name: "Total Tracks Duration", + value: `\`${ pms(queueDuration, { + colonNotation: true, + }) }\``, + inline: true, + }, + { + name: "Total Tracks", + value: `\`${ player.queue.totalSize - 1 }\``, + colonNotation: true, + inline: true, + }, + ) + .setFooter({ + text: `Page ${ page + 1 }/${ pages.length }`, + }); + + await interaction.editReply({ + embeds: [embedFour], + components: [ + new MessageActionRow().addComponents([buttonTwo, buttonOne]), + ], + }); + } else if (button.customId === "queue_cmd_but_2_app") { + await button.deferUpdate().catch(() => { + }); + page = page > 0? --page : pages.length - 1; + let song = player.queue.current; + var title = escapeMarkdown(song.title) + var title = title.replace(/\]/g,"") + var title = title.replace(/\[/g,"") + const embedFive = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `**â™Ē | Now playing:** [${ title }](${ song.uri }) [${ player.queue.current.requester }]\n\n**Queued Tracks**\n${ pages[page] }`, + ) + .addFields( + { + name: "Track Duration", + value: song.isStream + ? `\`LIVE\`` + : `\`${ pms(player.position, { colonNotation: true }) } / ${ pms( + player.queue.current.duration, + { colonNotation: true }, + ) }\``, + inline: true, + }, + { + name: "Total Tracks Duration", + value: `\`${ pms(queueDuration, { + colonNotation: true, + }) }\``, + inline: true, + }, + { + name: "Total Tracks", + value: `\`${ player.queue.totalSize - 1 }\``, + colonNotation: true, + inline: true, + }, + ) + .setFooter({ + text: `Page ${ page + 1 }/${ pages.length }`, + }); + + await interaction + .editReply({ + embeds: [embedFive], + components: [ + new MessageActionRow().addComponents([buttonTwo, buttonOne]), + ], + }) + .catch(() => { + }); + } else { + return; + } + }); + } + } + }); + +module.exports = command; diff --git a/commands/slash/reload.js b/commands/slash/reload.js new file mode 100644 index 0000000..c208790 --- /dev/null +++ b/commands/slash/reload.js @@ -0,0 +1,89 @@ +const { MessageEmbed, message } = require("discord.js"); +const SlashCommand = require("../../lib/SlashCommand"); +const fs = require("fs"); +const path = require("path"); + +const command = new SlashCommand() + .setName("reload") + .setDescription("Reload all commands") + .setRun(async (client, interaction, options) => { + if (interaction.user.id === client.config.adminId) { + try { + let ContextCommandsDirectory = path.join(__dirname, "..", "context"); + fs.readdir(ContextCommandsDirectory, (err, files) => { + files.forEach((file) => { + delete require.cache[ + require.resolve(ContextCommandsDirectory + "/" + file) + ]; + let cmd = require(ContextCommandsDirectory + "/" + file); + if (!cmd.command || !cmd.run) { + return this.warn( + "❌ Unable to load Command: " + + file.split(".")[0] + + ", File doesn't have either command/run", + ); + } + client.contextCommands.set(file.split(".")[0].toLowerCase(), cmd); + }); + }); + + let SlashCommandsDirectory = path.join(__dirname, "..", "slash"); + fs.readdir(SlashCommandsDirectory, (err, files) => { + files.forEach((file) => { + delete require.cache[ + require.resolve(SlashCommandsDirectory + "/" + file) + ]; + let cmd = require(SlashCommandsDirectory + "/" + file); + + if (!cmd || !cmd.run) { + return client.warn( + "❌ Unable to load Command: " + + file.split(".")[0] + + ", File doesn't have a valid command with run function", + ); + } + client.slashCommands.set(file.split(".")[0].toLowerCase(), cmd); + }); + }); + + const totalCmds = + client.slashCommands.size + client.contextCommands.size; + client.log(`Reloaded ${ totalCmds } commands!`); + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`Sucessfully Reloaded \`${ totalCmds }\` Commands!`) + .setFooter({ + text: `${ client.user.username } was reloaded by ${ interaction.user.username }`, + }) + .setTimestamp(), + ], + ephemeral: true, + }); + } catch (err) { + console.log(err); + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + "An error has occured. For more details please check console.", + ), + ], + ephemeral: true, + }); + } + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("You are not authorized to use this command!"), + ], + ephemeral: true, + }); + } + }); + +module.exports = command; diff --git a/commands/slash/remove.js b/commands/slash/remove.js new file mode 100644 index 0000000..c0a8b39 --- /dev/null +++ b/commands/slash/remove.js @@ -0,0 +1,68 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("remove") + .setDescription("Remove track you don't want from queue") + .addNumberOption((option) => + option + .setName("number") + .setDescription("Enter track number.") + .setRequired(true), + ) + + .setRun(async (client, interaction) => { + const args = interaction.options.getNumber("number"); + + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There are no songs to remove."), + ], + ephemeral: true, + }); + } + + await interaction.deferReply(); + + const position = Number(args) - 1; + if (position > player.queue.size) { + let thing = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `Current queue has only **${ player.queue.size }** track`, + ); + return interaction.editReply({ embeds: [thing] }); + } + + const song = player.queue[position]; + player.queue.remove(position); + + const number = position + 1; + let removeEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`Removed track number **${ number }** from queue`); + return interaction.editReply({ embeds: [removeEmbed] }); + }); + +module.exports = command; diff --git a/commands/slash/replay.js b/commands/slash/replay.js new file mode 100644 index 0000000..b3dd2ed --- /dev/null +++ b/commands/slash/replay.js @@ -0,0 +1,51 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("replay") + .setDescription("Replay current playing track") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("I'm not playing anything."), + ], + ephemeral: true, + }); + } + + await interaction.deferReply(); + + player.seek(0); + + let song = player.queue.current; + return interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`Replay [${ song.title }](${ song.uri })`), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/resume.js b/commands/slash/resume.js new file mode 100644 index 0000000..cfe9787 --- /dev/null +++ b/commands/slash/resume.js @@ -0,0 +1,57 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("resume") + .setDescription("Resume current track") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There is no song playing right now."), + ], + ephemeral: true, + }); + } + + if (!player.paused) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Current track is already resumed"), + ], + ephemeral: true, + }); + } + player.pause(false); + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`⏯ **Resumed!**`), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/save.js b/commands/slash/save.js new file mode 100644 index 0000000..957aac0 --- /dev/null +++ b/commands/slash/save.js @@ -0,0 +1,81 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); +const prettyMilliseconds = require("pretty-ms"); + +const command = new SlashCommand() + .setName("save") + .setDescription("Saves current song to your DM's") + .setRun(async (client, interaction) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There is no music playing right now."), + ], + ephemeral: true, + }); + } + + const sendtoDmEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setAuthor({ + name: "Saved track", + iconURL: `${ interaction.user.displayAvatarURL({ dynamic: true }) }`, + }) + .setDescription( + `**Saved [${ player.queue.current.title }](${ player.queue.current.uri }) to your DM**`, + ) + .addFields( + { + name: "Track Duration", + value: `\`${ prettyMilliseconds(player.queue.current.duration, { + colonNotation: true, + }) }\``, + inline: true, + }, + { + name: "Track Author", + value: `\`${ player.queue.current.author }\``, + inline: true, + }, + { + name: "Requested Guild", + value: `\`${ interaction.guild }\``, + inline: true, + }, + ); + + interaction.user.send({ embeds: [sendtoDmEmbed] }); + + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + "Please check your **DMs**. If you didn't receive any message from me please make sure your **DMs** are open", + ), + ], + ephemeral: true, + }); + }); + +module.exports = command; diff --git a/commands/slash/search.js b/commands/slash/search.js new file mode 100644 index 0000000..20a304d --- /dev/null +++ b/commands/slash/search.js @@ -0,0 +1,190 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const prettyMilliseconds = require("pretty-ms"); +const { + MessageEmbed, + MessageActionRow, + MessageSelectMenu, +} = require("discord.js"); + +const command = new SlashCommand() + .setName("search") + .setDescription("Search for a song") + .addStringOption((option) => + option + .setName("query") + .setDescription("The song to search for") + .setRequired(true) + ) + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.createPlayer(interaction.channel, channel); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + await interaction.deferReply().catch((_) => {}); + + if (player.state !== "CONNECTED") { + player.connect(); + } + + const search = interaction.options.getString("query"); + let res; + + try { + res = await player.search(search, interaction.user); + if (res.loadType === "LOAD_FAILED") { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setDescription("An error occured while searching for the song") + .setColor("RED"), + ], + ephemeral: true, + }); + } + } catch (err) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setAuthor({ + name: "An error occured while searching for the song", + }) + .setColor("RED"), + ], + ephemeral: true, + }); + } + + if (res.loadType == "NO_MATCHES") { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setDescription(`No results found for \`${search}\``) + .setColor("RED"), + ], + ephemeral: true, + }); + } else { + let max = 10; + if (res.tracks.length < max) { + max = res.tracks.length; + } + + let resultFromSearch = []; + + res.tracks.slice(0, max).map((track) => { + resultFromSearch.push({ + label: `${track.title}`, + value: `${track.uri}`, + description: track.isStream + ? `LIVE` + : `${prettyMilliseconds(track.duration, { + secondsDecimalDigits: 0, + })} - ${track.author}`, + }); + }); + + const menus = new MessageActionRow().addComponents( + new MessageSelectMenu() + .setCustomId("select") + .setPlaceholder("Select a song") + .addOptions(resultFromSearch) + ); + + let choosenTracks = await interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `Here are some of the results I found for \`${search}\`. Please select track within \`30 seconds\`` + ), + ], + components: [menus], + }); + const filter = (button) => button.user.id === interaction.user.id; + + const tracksCollector = choosenTracks.createMessageComponentCollector({ + filter, + time: 30000, + }); + tracksCollector.on("collect", async (i) => { + if (i.isSelectMenu()) { + await i.deferUpdate(); + let uriFromCollector = i.values[0]; + let trackForPlay; + + trackForPlay = await player?.search( + uriFromCollector, + interaction.user + ); + player?.queue?.add(trackForPlay.tracks[0]); + if (!player?.playing && !player?.paused && !player?.queue?.size) { + player?.play(); + } + i.editReply({ + content: null, + embeds: [ + new MessageEmbed() + .setAuthor({ + name: "Added to queue", + iconURL: client.config.iconURL, + }) + .setURL(res.tracks[0].uri) + .setThumbnail(res.tracks[0].displayThumbnail("maxresdefault")) + .setDescription( + `[${trackForPlay?.tracks[0]?.title}](${trackForPlay?.tracks[0].uri})` || + "No Title" + ) + .addFields( + { + name: "Added by", + value: `<@${interaction.user.id}>`, + inline: true, + }, + { + name: "Duration", + value: res.tracks[0].isStream + ? `\`LIVE :red_circle:\`` + : `\`${client.ms(res.tracks[0].duration, { + colonNotation: true, + })}\``, + inline: true, + } + ) + .setColor(client.config.embedColor), + ], + components: [], + }); + } + }); + tracksCollector.on("end", async (i) => { + if (i.size == 0) { + choosenTracks.edit({ + content: null, + embeds: [ + new MessageEmbed() + .setDescription( + `No track selected. You took too long to select a track.` + ) + .setColor(client.config.embedColor), + ], + components: [], + }); + } + }); + } + }); + +module.exports = command; diff --git a/commands/slash/seek.js b/commands/slash/seek.js new file mode 100644 index 0000000..5540ea8 --- /dev/null +++ b/commands/slash/seek.js @@ -0,0 +1,82 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); +const ms = require("ms"); + +const command = new SlashCommand() + .setName("seek") + .setDescription("Seek to a specific time in the current song.") + .addStringOption((option) => + option + .setName("time") + .setDescription("Seek to time you want. Ex 1h 30m | 2h | 80m | 53s") + .setRequired(true), + ) + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There is no music playing."), + ], + ephemeral: true, + }); + } + + await interaction.deferReply(); + + const rawArgs = interaction.options.getString("time"); + const args = rawArgs.split(' '); + var rawTime = []; + for (i = 0; i < args.length; i++){ + rawTime.push(ms(args[i])); + } + const time = rawTime.reduce((a,b) => a + b, 0); + const position = player.position; + const duration = player.queue.current.duration; + + if (time <= duration) { + player.seek(time); + return interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `⏊ | **${ player.queue.current.title }** has been ${ + time < position? "rewound" : "seeked" + } to **${ ms(time) }**`, + ), + ], + }); + } else { + return interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `Unable to seek current playing track. This may be due to exceeding track duration or an incorrect time format. Please check and try again`, + ), + ], + }); + } + }); + +module.exports = command; diff --git a/commands/slash/shuffle.js b/commands/slash/shuffle.js new file mode 100644 index 0000000..97bc0f0 --- /dev/null +++ b/commands/slash/shuffle.js @@ -0,0 +1,59 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("shuffle") + .setDescription("Randomizes the queue") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There is no music playing."), + ], + ephemeral: true, + }); + } + + if (!player.queue || !player.queue.length || player.queue.length === 0) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There are not enough songs in the queue."), + ], + ephemeral: true, + }); + } + + // if the queue is not empty, shuffle the entire queue + player.queue.shuffle(); + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("🔀 | **Successfully shuffled the queue.**"), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/skip.js b/commands/slash/skip.js new file mode 100644 index 0000000..5482540 --- /dev/null +++ b/commands/slash/skip.js @@ -0,0 +1,59 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("skip") + .setDescription("Skip the current song") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There is nothing to skip."), + ], + ephemeral: true, + }); + } + const song = player.queue.current; + const autoQueue = player.get("autoQueue"); + if (player.queue[0] == undefined && (!autoQueue || autoQueue === false)) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription(`There is nothing after [${ song.title }](${ song.uri }) in the queue.`), + ], + })} + + player.queue.previous = player.queue.current; + player.stop(); + + interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("✅ | **Skipped!**"), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/skipto.js b/commands/slash/skipto.js new file mode 100644 index 0000000..fb1b33c --- /dev/null +++ b/commands/slash/skipto.js @@ -0,0 +1,81 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("skipto") + .setDescription("skip to a specific song in the queue") + .addNumberOption((option) => + option + .setName("number") + .setDescription("The number of tracks to skipto") + .setRequired(true), + ) + + .setRun(async (client, interaction, options) => { + const args = interaction.options.getNumber("number"); + //const duration = player.queue.current.duration + + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("I'm not in a channel."), + ], + ephemeral: true, + }); + } + + await interaction.deferReply(); + + const position = Number(args); + + try { + if (!position || position < 0 || position > player.queue.size) { + let thing = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("❌ | Invalid position!"); + return interaction.editReply({ embeds: [thing] }); + } + + player.queue.remove(0, position - 1); + player.stop(); + + let thing = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("✅ | Skipped to position " + position); + + return interaction.editReply({ embeds: [thing] }); + } catch { + if (position === 1) { + player.stop(); + } + return interaction.editReply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription("✅ | Skipped to position " + position), + ], + }); + } + }); + +module.exports = command; diff --git a/commands/slash/stats.js b/commands/slash/stats.js new file mode 100644 index 0000000..f521659 --- /dev/null +++ b/commands/slash/stats.js @@ -0,0 +1,89 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const moment = require("moment"); +require("moment-duration-format"); +const { MessageEmbed } = require("discord.js"); +const os = require("os"); + +const command = new SlashCommand() + .setName("stats") + .setDescription("Get information about the bot") + .setRun(async (client, interaction) => { + // get OS info + const osver = os.platform() + " " + os.release(); + + // Get nodejs version + const nodeVersion = process.version; + + // get the uptime in a human readable format + const runtime = moment + .duration(client.uptime) + .format("d[ Days]ãƒģh[ Hrs]ãƒģm[ Mins]ãƒģs[ Secs]"); + // show lavalink uptime in a nice format + const lavauptime = moment + .duration(client.manager.nodes.values().next().value.stats.uptime) + .format(" D[d], H[h], m[m]"); + // show lavalink memory usage in a nice format + const lavaram = ( + client.manager.nodes.values().next().value.stats.memory.used / + 1024 / + 1024 + ).toFixed(2); + // sow lavalink memory alocated in a nice format + const lavamemalocated = ( + client.manager.nodes.values().next().value.stats.memory.allocated / + 1024 / + 1024 + ).toFixed(2); + // show system uptime + var sysuptime = moment + .duration(os.uptime() * 1000) + .format("d[ Days]ãƒģh[ Hrs]ãƒģm[ Mins]ãƒģs[ Secs]"); + + // get commit hash and date + let gitHash = "unknown"; + try { + gitHash = require("child_process") + .execSync("git rev-parse HEAD") + .toString() + .trim(); + } catch (e) { + // do nothing + gitHash = "unknown"; + } + + const statsEmbed = new MessageEmbed() + .setTitle(`${ client.user.username } Information`) + .setColor(client.config.embedColor) + .setDescription( + `\`\`\`yml\nName: ${ client.user.username }#${ client.user.discriminator } [${ client.user.id }]\nAPI: ${ client.ws.ping }ms\nRuntime: ${ runtime }\`\`\``, + ) + .setFields([ + { + name: `Lavalink stats`, + value: `\`\`\`yml\nUptime: ${ lavauptime }\nRAM: ${ lavaram } MB\nPlaying: ${ + client.manager.nodes.values().next().value.stats.playingPlayers + } out of ${ + client.manager.nodes.values().next().value.stats.players + }\`\`\``, + inline: true, + }, + { + name: "Bot stats", + value: `\`\`\`yml\nGuilds: ${ + client.guilds.cache.size + } \nNodeJS: ${ nodeVersion }\nDiscordMusicBot: v${ + require("../../package.json").version + } \`\`\``, + inline: true, + }, + { + name: "System stats", + value: `\`\`\`yml\nOS: ${ osver }\nUptime: ${ sysuptime }\n\`\`\``, + inline: false, + }, + ]) + .setFooter({ text: `Build: ${ gitHash }` }); + return interaction.reply({ embeds: [statsEmbed], ephemeral: false }); + }); + +module.exports = command; diff --git a/commands/slash/stop.js b/commands/slash/stop.js new file mode 100644 index 0000000..7de8d48 --- /dev/null +++ b/commands/slash/stop.js @@ -0,0 +1,55 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("stop") + .setDescription("Stops whatever the bot is playing and leaves the voice channel\n(This command will clear the queue)") + + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("I'm not in a channel."), + ], + ephemeral: true, + }); + } + + if (player.twentyFourSeven) { + player.queue.clear(); + player.stop(); + player.set("autoQueue", false); + } else { + player.destroy(); + } + + interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription(`:wave: | **Bye Bye!**`), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/summon.js b/commands/slash/summon.js new file mode 100644 index 0000000..4aa7d95 --- /dev/null +++ b/commands/slash/summon.js @@ -0,0 +1,36 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("summon") + .setDescription("Summons the bot to the channel.") + .setRun(async (client, interaction, options) => { + let channel = await client.getChannel(client, interaction); + if (!interaction.member.voice.channel) { + const joinEmbed = new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + "❌ | **You must be in a voice channel to use this command.**", + ); + return interaction.reply({ embeds: [joinEmbed], ephemeral: true }); + } + + let player = client.manager.players.get(interaction.guild.id); + if (!player) { + player = client.createPlayer(interaction.channel, channel); + player.connect(true); + } + + if (channel.id !== player.voiceChannel) { + player.setVoiceChannel(channel.id); + player.connect(); + } + + interaction.reply({ + embeds: [ + client.Embed(`:thumbsup: | **Successfully joined <#${ channel.id }>!**`), + ], + }); + }); + +module.exports = command; diff --git a/commands/slash/volume.js b/commands/slash/volume.js new file mode 100644 index 0000000..5074198 --- /dev/null +++ b/commands/slash/volume.js @@ -0,0 +1,68 @@ +const SlashCommand = require("../../lib/SlashCommand"); +const { MessageEmbed } = require("discord.js"); + +const command = new SlashCommand() + .setName("volume") + .setDescription("Change the volume of the current song.") + .addNumberOption((option) => + option + .setName("amount") + .setDescription("Amount of volume you want to change. Ex: 10") + .setRequired(false), + ) + .setRun(async (client, interaction) => { + let channel = await client.getChannel(client, interaction); + if (!channel) { + return; + } + + let player; + if (client.manager) { + player = client.manager.players.get(interaction.guild.id); + } else { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("Lavalink node is not connected"), + ], + }); + } + + if (!player) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor("RED") + .setDescription("There is no music playing."), + ], + ephemeral: true, + }); + } + + let vol = interaction.options.getNumber("amount"); + if (!vol || vol < 1 || vol > 125) { + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `:loud_sound: | Current volume **${ player.volume }**`, + ), + ], + }); + } + + player.setVolume(vol); + return interaction.reply({ + embeds: [ + new MessageEmbed() + .setColor(client.config.embedColor) + .setDescription( + `:loud_sound: | Successfully set volume to **${ player.volume }**`, + ), + ], + }); + }); + +module.exports = command; diff --git a/config.js b/config.js new file mode 100644 index 0000000..64a7bcb --- /dev/null +++ b/config.js @@ -0,0 +1,48 @@ +module.exports = { + helpCmdPerPage: 10, //- Number of commands per page of help command + lyricsMaxResults: 5, //- Number of results for lyrics command (Do not touch this value if you don't know what you are doing) + adminId: "UserId", //- Replace UserId with the Discord ID of the admin of the bot + token: process.env.token || "", //- Bot's Token + clientId: process.env.clientId || "", //- ID of the bot + clientSecret: process.env.clientSecret || "", //- Client Secret of the bot + port: 4200, //- Port of the API and Dashboard + scopes: ["identify", "guilds", "applications.commands"], //- Discord OAuth2 Scopes + serverDeafen: true, //- If you want bot to stay deafened + defaultVolume: 100, //- Sets the default volume of the bot, You can change this number anywhere from 1 to 100 + supportServer: "https://discord.gg/discord", //- Support Server Link + Issues: "https://github.com/BestGamersH/Music-bot/issues", //- Bug Report Link + permissions: 277083450689, //- Bot Inviting Permissions + disconnectTime: 30000, //- How long should the bot wait before disconnecting from the voice channel (in miliseconds). Set to 1 for instant disconnect. + twentyFourSeven: false, //- When set to true, the bot will never disconnect from the voice channel + autoQueue: false, //- When set to true, related songs will automatically be added to the queue + autoPause: true, //- When set to true, music will automatically be paused if everyone leaves the voice channel + autoLeave: false, //- When set to true, the bot will automatically leave when no one is in the voice channel (can be combined with 24/7 to always be in voice channel until everyone leaves; if 24/7 is on disconnectTime will add a disconnect delay after everyone leaves.) + debug: false, //- Debug mode + cookieSecret: "BestGamersHK is cool", //- Cookie Secret + website: "http://localhost:4200", //- without the / at the end + // You need a lavalink server for this bot to work!!!! + // Lavalink server; public lavalink -> https://lavalink-list.darrennathanael.com/; create one yourself -> https://darrennathanael.com/post/how-to-lavalink + nodes: [ + { + identifier: "Main Node", //- Used for indentifier in stats commands. + host: "", //- The host name or IP of the lavalink server. + port: 80, // The port that lavalink is listening to. This must be a number! + password: "", //- The password of the lavalink server. + retryAmount: 200, //- The amount of times to retry connecting to the node if connection got dropped. + retryDelay: 40, //- Delay between reconnect attempts if connection is lost. + secure: false, //- Can be either true or false. Only use true if ssl is enabled! + }, + ], + embedColor: "#2f3136", //- Color of the embeds, hex supported + presence: { + // PresenceData object | https://discord.js.org/#/docs/main/stable/typedef/PresenceData + status: "online", //- You can have online, idle, dnd and invisible (Note: invisible makes people think the bot is offline) + activities: [ + { + name: "Music", //- Status Text + type: "LISTENING", //- PLAYING, WATCHING, LISTENING, STREAMING + }, + ], + }, + iconURL: "https://cdn.darrennathanael.com/icons/spinning_disk.gif", //- This icon will be in every embed's author field +}; diff --git a/dashboard/.eslintrc.json b/dashboard/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/dashboard/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/dashboard/.gitignore b/dashboard/.gitignore new file mode 100644 index 0000000..bf920c1 --- /dev/null +++ b/dashboard/.gitignore @@ -0,0 +1,31 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel diff --git a/dashboard/README.md b/dashboard/README.md new file mode 100644 index 0000000..0ca9b95 --- /dev/null +++ b/dashboard/README.md @@ -0,0 +1,41 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped +with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed +on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited +in `pages/api/hello.js`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated +as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions +are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use +the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) +from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/dashboard/components/StatCard.tsx b/dashboard/components/StatCard.tsx new file mode 100644 index 0000000..3acb157 --- /dev/null +++ b/dashboard/components/StatCard.tsx @@ -0,0 +1,20 @@ +import {Card, Text} from "@nextui-org/react"; +import {ReactNode} from "react"; + +export default function StatCard(props: { + title: string; + amount: number | string; + icon: ReactNode; +}) { + return ( + + +
+ { props.title } + { props.amount } +
+ { props.icon } +
+
+ ) +} \ No newline at end of file diff --git a/dashboard/components/content.tsx b/dashboard/components/content.tsx new file mode 100644 index 0000000..b86a699 --- /dev/null +++ b/dashboard/components/content.tsx @@ -0,0 +1,17 @@ +import {PropsWithChildren} from "react"; +import Navbar from "./navbar"; + +export default function Content(props: PropsWithChildren) { + return
+ +
+ { props.children } +
+
+} \ No newline at end of file diff --git a/dashboard/components/navbar.tsx b/dashboard/components/navbar.tsx new file mode 100644 index 0000000..f38ab44 --- /dev/null +++ b/dashboard/components/navbar.tsx @@ -0,0 +1,31 @@ +import {Button, Link, Spacer} from "@nextui-org/react"; +import { useRouter } from "next/router"; + +export default function Navbar() { + const router = useRouter(); + + return
+ Discord Music Bot + + + + +
+} diff --git a/dashboard/components/server.tsx b/dashboard/components/server.tsx new file mode 100644 index 0000000..2d4c566 --- /dev/null +++ b/dashboard/components/server.tsx @@ -0,0 +1,32 @@ +import {Avatar, Tooltip} from "@nextui-org/react"; +import Link from "next/link"; + +interface IProps { + icon: string; + name: string; + id: string; +} + +const getColor = () => { + let c = ["gradient", "primary", "secondary", "error", "warning"] + return c[Math.floor(Math.random() * c.length)]; +} + +export default function Server(props: IProps) { + return +} \ No newline at end of file diff --git a/dashboard/next-env.d.ts b/dashboard/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/dashboard/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/dashboard/next.config.js b/dashboard/next.config.js new file mode 100644 index 0000000..d139cfa --- /dev/null +++ b/dashboard/next.config.js @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, +} + +module.exports = nextConfig diff --git a/dashboard/out/404.html b/dashboard/out/404.html new file mode 100644 index 0000000..440d1e8 --- /dev/null +++ b/dashboard/out/404.html @@ -0,0 +1,12 @@ +404: This page could not be found

404

This page could not be found.

\ No newline at end of file diff --git a/dashboard/out/_next/static/chunks/123-d3ffcfb4730480c6.js b/dashboard/out/_next/static/chunks/123-d3ffcfb4730480c6.js new file mode 100644 index 0000000..74ba7b4 --- /dev/null +++ b/dashboard/out/_next/static/chunks/123-d3ffcfb4730480c6.js @@ -0,0 +1 @@ +(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[123],{1160:function(e,t,r){"use strict";r.d(t,{ZP:function(){return B}});var o=r(7294),n=r(9641),i=r(4213),s=r(7354);function a(e,t,r,o){Object.defineProperty(e,t,{get:r,set:o,enumerable:!0,configurable:!0})}function l(e,t){let r,{elementType:o="button",isDisabled:a,onPress:l,onPressStart:c,onPressEnd:d,onPressChange:u,preventFocusOnPress:b,allowFocusWhenDisabled:p,onClick:g,href:$,target:f,rel:h,type:m="button"}=e;r="button"===o?{type:m,disabled:a}:{role:"button",tabIndex:a?void 0:0,href:"a"===o&&a?void 0:$,target:"a"===o?f:void 0,type:"input"===o?m:void 0,disabled:"input"===o?a:void 0,"aria-disabled":a&&"input"!==o?a:void 0,rel:"a"===o?h:void 0};let{pressProps:x,isPressed:v}=(0,s.r7)({onPressStart:c,onPressEnd:d,onPressChange:u,onPress:l,isDisabled:a,preventFocusOnPress:b,ref:t}),{focusableProps:y}=(0,n.kc)(e,t);p&&(y.tabIndex=a?-1:y.tabIndex);let w=(0,i.dG)(y,x,(0,i.zL)(e,{labelable:!0}));return{isPressed:v,buttonProps:(0,i.dG)(r,w,{"aria-haspopup":e["aria-haspopup"],"aria-expanded":e["aria-expanded"],"aria-controls":e["aria-controls"],"aria-pressed":e["aria-pressed"],onClick:e=>{g&&(g(e),console.warn("onClick is deprecated, please use onPress"))}})}}a({},"useButton",(()=>l));function c(e,t,r){const{isSelected:o}=t,{isPressed:n,buttonProps:s}=l({...e,onPress:(0,i.tS)(t.toggle,e.onPress)},r);return{isPressed:n,buttonProps:(0,i.dG)(s,{"aria-pressed":o})}}a({},"useToggleButton",(()=>c));const d={};var u=(e,t)=>{const r=`[Next UI]${t?` [${t}]`:" "}: ${e}`;"undefined"==typeof console||d[r]||(d[r]=!0,console.warn(r))},b=r(8375);const p=o.createContext({isButtonGroup:!1,disabled:!1});var g=r(6212),$=r(88),f=r(1309),h=r(5893);const m=(0,g.zo)("span",{dflex:"center",position:"absolute",left:"$$buttonPadding",right:"auto",top:"50%",transform:"translateY(-50%)",color:"inherit",zIndex:"$1","& svg":{background:"transparent"},variants:{isAuto:{true:{position:"relative",transform:"none",top:"0%"}},isRight:{true:{right:"$$buttonPadding",left:"auto"}},isSingle:{true:{position:"static",transform:"none"}},isGradientButtonBorder:{true:{}}},compoundVariants:[{isAuto:!0,isRight:!0,isSingle:!1,css:{order:2,ml:"calc($$buttonPadding / 2)",right:"0%",left:"0%"}},{isAuto:!0,isRight:!1,isSingle:!1,css:{order:0,mr:"calc($$buttonPadding / 2)",right:"0%",left:"0%"}},{isSingle:!0,isRight:!1,css:{ml:0}},{isSingle:!0,isRight:!0,css:{mr:0}},{isSingle:!0,isRight:!1,isGradientButtonBorder:!0,css:{mr:"calc($$buttonPadding / 2)"}}]}),x=({children:e,className:t,css:r,...o})=>(0,h.jsx)(m,{className:(0,f.Z)("nextui-button-icon",{"nextui-button-icon-right":o.isRight,"nextui-button-icon-single":o.isSingle},t),css:{...r},...o,children:e});x.toString=()=>".nextui-button-icon";const v=o.memo(x);var y=(0,$.Z)(v,{className:""}),w=r(9260),S=r(9975);var C=(0,g.zo)("button",{$$buttonBorderRadius:"$radii$md",$$buttonPressedScale:.97,dflex:"center",appearance:"none",boxSizing:"border-box",fontWeight:"$medium",us:"none",lineHeight:"$sm",ta:"center",whiteSpace:"nowrap",transition:"$button",position:"relative",overflow:"hidden",border:"none",cursor:"pointer",pe:"auto",p:0,br:"$$buttonBorderRadius","@motion":{transition:"none"},".nextui-button-text":{dflex:"center",zIndex:"$2","p, pre, div":{margin:0}},[`& ${b.q}`]:{zIndex:"$1",".nextui-drip-filler":{opacity:.25,fill:"$accents2"}},variants:{bordered:{true:{bg:"transparent",borderStyle:"solid",color:"$text"}},ghost:{true:{}},color:{default:{bg:"$primary",color:"$primarySolidContrast"},primary:{bg:"$primary",color:"$primarySolidContrast"},secondary:{bg:"$secondary",color:"$secondarySolidContrast"},success:{bg:"$success",color:"$successSolidContrast"},warning:{bg:"$warning",color:"$warningSolidContrast"},error:{bg:"$error",color:"$errorSolidContrast"},gradient:{bg:"$gradient",color:"$primarySolidContrast"}},size:{xs:{$$buttonPadding:"$space$3",$$buttonBorderRadius:"$radii$xs",$$buttonHeight:"$space$10",px:"$3",height:"$$buttonHeight",lh:"$space$10",width:"auto",minWidth:"$20",fontSize:"$xs"},sm:{$$buttonPadding:"$space$5",$$buttonBorderRadius:"$radii$sm",$$buttonHeight:"$space$12",px:"$5",height:"$$buttonHeight",lh:"$space$14",width:"auto",minWidth:"$36",fontSize:"$sm"},md:{$$buttonPadding:"$space$7",$$buttonBorderRadius:"$radii$md",$$buttonHeight:"$space$14",px:"$7",height:"$$buttonHeight",lh:"$space$14",width:"auto",minWidth:"$48",fontSize:"$sm"},lg:{$$buttonPadding:"$space$9",$$buttonBorderRadius:"$radii$base",$$buttonHeight:"$space$16",px:"$9",height:"$$buttonHeight",lh:"$space$15",width:"auto",minWidth:"$60",fontSize:"$md"},xl:{$$buttonPadding:"$space$10",$$buttonBorderRadius:"$radii$xl",$$buttonHeight:"$space$18",px:"$10",height:"$$buttonHeight",lh:"$space$17",width:"auto",minWidth:"$72",fontSize:"$lg"}},borderWeight:{light:{bw:"$light",$$buttonBorderWeight:"$borderWeights$light"},normal:{bw:"$normal",$$buttonBorderWeight:"$borderWeights$normal"},bold:{bw:"$bold",$$buttonBorderWeight:"$borderWeights$bold"},extrabold:{bw:"$extrabold",$$buttonBorderWeight:"$borderWeights$extrabold"},black:{bw:"$black",$$buttonBorderWeight:"$borderWeights$black"}},flat:{true:{color:"$text"}},light:{true:{bg:"transparent",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.8,fill:"$accents2"}}}},shadow:{true:{bs:"$sm"}},animated:{false:{transition:"none"}},auto:{true:{width:"auto",minWidth:"min-content"}},rounded:{true:{$$buttonBorderRadius:"$radii$pill"}},isPressed:{true:{}},isHovered:{true:{}},isChildLess:{true:{p:0,width:"$$buttonHeight",height:"$$buttonHeight"}}},compoundVariants:[{isPressed:!0,animated:!0,css:{transform:"scale($$buttonPressedScale)"}},{auto:!0,isChildLess:!1,size:"xs",css:{px:"$5",minWidth:"min-content"}},{auto:!0,isChildLess:!1,size:"sm",css:{px:"$8",minWidth:"min-content"}},{auto:!0,isChildLess:!1,size:"md",css:{px:"$9",minWidth:"min-content"}},{auto:!0,isChildLess:!1,size:"lg",css:{px:"$10",minWidth:"min-content"}},{auto:!0,isChildLess:!1,size:"xl",css:{px:"$11",minWidth:"min-content"}},{shadow:!0,color:"default",css:{normalShadow:"$primaryShadow"}},{shadow:!0,color:"primary",css:{normalShadow:"$primaryShadow"}},{shadow:!0,color:"secondary",css:{normalShadow:"$secondaryShadow"}},{shadow:!0,color:"warning",css:{normalShadow:"$warningShadow"}},{shadow:!0,color:"success",css:{normalShadow:"$successShadow"}},{shadow:!0,color:"error",css:{normalShadow:"$errorShadow"}},{shadow:!0,color:"gradient",css:{normalShadow:"$primaryShadow"}},{light:!0,color:"default",css:{bg:"transparent",color:"$text",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.8,fill:"$primaryLightActive"}}}},{light:!0,color:"primary",css:{bg:"transparent",color:"$primary",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.8,fill:"$primaryLightActive"}}}},{light:!0,color:"secondary",css:{bg:"transparent",color:"$secondary",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.8,fill:"$secondaryLightActive"}}}},{light:!0,color:"warning",css:{bg:"transparent",color:"$warning",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.8,fill:"$warningLightActive"}}}},{light:!0,color:"success",css:{bg:"transparent",color:"$success",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.8,fill:"$successLightActive"}}}},{light:!0,color:"error",css:{bg:"transparent",color:"$error",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.8,fill:"$errorLightActive"}}}},{bordered:!0,color:"default",css:{bg:"transparent",borderColor:"$primary",color:"$primary",[`& ${b.q}`]:{".nextui-drip-filler":{fill:"$primary"}}}},{bordered:!0,color:"primary",css:{bg:"transparent",borderColor:"$primary",color:"$primary",[`& ${b.q}`]:{".nextui-drip-filler":{fill:"$primary"}}}},{bordered:!0,color:"secondary",css:{bg:"transparent",borderColor:"$secondary",color:"$secondary",[`& ${b.q}`]:{".nextui-drip-filler":{fill:"$secondary"}}}},{bordered:!0,color:"success",css:{bg:"transparent",borderColor:"$success",color:"$success",[`& ${b.q}`]:{".nextui-drip-filler":{fill:"$success"}}}},{bordered:!0,color:"warning",css:{bg:"transparent",borderColor:"$warning",color:"$warning",[`& ${b.q}`]:{".nextui-drip-filler":{fill:"$warning"}}}},{bordered:!0,color:"error",css:{bg:"transparent",borderColor:"$error",color:"$error",[`& ${b.q}`]:{".nextui-drip-filler":{fill:"$error"}}}},{bordered:!0,color:"gradient",css:{bg:"transparent",color:"$text",padding:"$$buttonBorderWeight",bgClip:"content-box, border-box",borderColor:"$primary",backgroundImage:"linear-gradient($background, $background), $gradient",border:"none",[`& ${b.q}`]:{".nextui-drip-filler":{fill:"$secondary"}}}},{ghost:!0,isHovered:!0,color:"default",css:{bg:"$primary",color:"$primarySolidContrast"}},{ghost:!0,isHovered:!0,color:"primary",css:{bg:"$primary",color:"$primarySolidContrast"}},{ghost:!0,isHovered:!0,color:"secondary",css:{bg:"$secondary",color:"$secondarySolidContrast"}},{ghost:!0,isHovered:!0,color:"success",css:{bg:"$success",color:"$successSolidContrast"}},{ghost:!0,isHovered:!0,color:"warning",css:{bg:"$warning",color:"$warningSolidContrast"}},{ghost:!0,isHovered:!0,color:"error",css:{bg:"$error",color:"$errorSolidContrast"}},{ghost:!0,color:"gradient",isHovered:!0,css:{bg:"$gradient",color:"$white"}},{flat:!0,color:"default",css:{bg:"$primaryLight",color:"$primaryLightContrast",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.4,fill:"$primary"}}}},{flat:!0,color:"primary",css:{bg:"$primaryLight",color:"$primaryLightContrast",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.4,fill:"$primary"}}}},{flat:!0,color:"secondary",css:{bg:"$secondaryLight",color:"$secondaryLightContrast",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.4,fill:"$secondary"}}}},{flat:!0,color:"success",css:{bg:"$successLight",color:"$successLightContrast",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.4,fill:"$success"}}}},{flat:!0,color:"warning",css:{bg:"$warningLight",color:"$warningLightContrast",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.4,fill:"$warning"}}}},{flat:!0,color:"error",css:{bg:"$errorLight",color:"$errorLightContrast",[`& ${b.q}`]:{".nextui-drip-filler":{opacity:.4,fill:"$error"}}}},{flat:!0,isHovered:!0,color:"default",css:{bg:"$primaryLightHover"}},{flat:!0,isHovered:!0,color:"primary",css:{bg:"$primaryLightHover"}},{flat:!0,isHovered:!0,color:"secondary",css:{bg:"$secondaryLightHover"}},{flat:!0,isHovered:!0,color:"success",css:{bg:"$successLightHover"}},{flat:!0,isHovered:!0,color:"warning",css:{bg:"$warningLightHover"}},{flat:!0,isHovered:!0,color:"error",css:{bg:"$errorLightHover"}},{flat:!0,isPressed:!0,color:"default",css:{bg:"$primaryLightActive"}},{flat:!0,isPressed:!0,color:"primary",css:{bg:"$primaryLightActive"}},{flat:!0,isPressed:!0,color:"secondary",css:{bg:"$secondaryLightActive"}},{flat:!0,isPressed:!0,color:"success",css:{bg:"$successLightActive"}},{flat:!0,isPressed:!0,color:"warning",css:{bg:"$warningLightActive"}},{flat:!0,isPressed:!0,color:"error",css:{bg:"$errorLightActive"}},{auto:!0,color:"gradient",bordered:!0,css:{".nextui-button-text":{px:"$$buttonPadding"},".nextui-button-icon":{ml:"$$buttonPadding"},".nextui-button-icon-right":{mr:"$$buttonPadding"},".nextui-button-text-left":{pl:0},".nextui-button-text-right":{pr:0}}},{rounded:!0,size:"xs",css:{br:"$pill"}},{rounded:!0,size:"sm",css:{br:"$pill"}},{rounded:!0,size:"md",css:{br:"$pill"}},{rounded:!0,size:"lg",css:{br:"$pill"}},{rounded:!0,size:"xl",css:{br:"$pill"}}],defaultVariants:{color:"default",borderWeight:"normal",animated:!0,size:"md"}},S.BM,S.Oe),k=r(2903),P=r(3569);const N=o.forwardRef((({as:e,css:t,iconLeftCss:r,iconRightCss:a,onClick:c,onPress:d,onPressStart:g,onPressEnd:$,onPressChange:m,onPressUp:x,...v},S)=>{const N=((e,t)=>{var r,o,n,i,s,a,l,c,d,u,b;return t.isButtonGroup?{...e,auto:!0,shadow:!1,bordered:null!=(r=t.bordered)?r:e.bordered,borderWeight:null!=(o=t.borderWeight)?o:e.borderWeight,ghost:null!=(n=t.ghost)?n:e.ghost,ripple:null!=(i=t.ripple)?i:e.ripple,flat:null!=(s=t.flat)?s:e.flat,animated:null!=(a=t.animated)?a:e.animated,rounded:null!=(l=t.rounded)?l:e.rounded,light:null!=(c=t.light)?c:e.light,size:null!=(d=t.size)?d:e.size,color:null!=(u=t.color)?u:e.color,disabled:null!=(b=t.disabled)?b:e.disabled}:e})(v,o.useContext(p)),E=(e=>{if(!e.disabled)return e.auto&&"gradient"===e.color&&(e.bordered||e.ghost)?{px:"$$buttonBorderWeight",py:"$$buttonBorderWeight"}:{};const t={bg:"$accents1",color:"$accents7",transform:"none",boxShadow:"none",pe:"none"};return e.bordered||e.flat||e.ghost||e.light?"gradient"===e.color&&(e.bordered||e.ghost)?{color:"$accents4",backgroundImage:"linear-gradient($background, $background), linear-gradient($accents2, $accents2)",transform:"none",boxShadow:"none",pe:"none",pl:"$$buttonBorderWeight",pr:"$$buttonBorderWeight"}:e.bordered||e.ghost||e.light?{...t,bg:"transparent",borderColor:"$accents4"}:e.flat?{...t,bg:"$accents1"}:{}:t})(N),{flat:L,children:F,disabled:R,animated:W,light:B,ripple:H,bordered:z,auto:j,borderWeight:A,icon:I,iconRight:T,ghost:q,autoFocus:V,className:G,...K}=N,M=e=>{W&&H&&D.current&&Q(e)},D=(0,k.gy)(S),{buttonProps:Z,isPressed:U}=l({...v,onClick:e=>{M(e),null==c||c(e)},isDisabled:R,elementType:e,onPress:e=>{"keyboard"!==e.pointerType&&"virtual"!==e.pointerType||(M(e),null==c||c(e)),null==d||d(e)},onPressStart:g,onPressEnd:$,onPressChange:m,onPressUp:x},D),{hoverProps:O,isHovered:_}=(0,s.XI)({isDisabled:R}),{isFocused:X,isFocusVisible:Y,focusProps:J}=(0,n.Fx)({autoFocus:V}),{onClick:Q,...ee}=(0,w.Z)(!1,D);P.Ts&&"gradient"===N.color&&(L||B)&&u("Using the gradient color on flat and light buttons will have no effect.");const te=I||T,re=0===o.Children.count(F),oe=Boolean(T),ne=(0,o.useMemo)((()=>U?"pressed":_?"hovered":R?"disabled":"ready"),[R,_,U]),ie=(0,o.useMemo)((()=>oe?a:r),[oe,a,r]);return(0,h.jsxs)(C,{as:e,ref:D,borderWeight:A,auto:j,flat:L,light:B,ghost:q,bordered:z||q,"data-state":ne,animated:W,isChildLess:re,isPressed:U,isHovered:_||q&&X,isFocusVisible:Y&&!R,className:(0,f.Z)("nextui-button",`nextui-button--${ne}`,G),css:{...t,...E},...(0,i.dG)(Z,J,O,K),children:[0===o.Children.count(F)?(0,h.jsx)(y,{isSingle:!0,isAuto:j,isRight:oe,css:ie,isGradientButtonBorder:"gradient"===K.color&&(z||q),children:te}):te?(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(y,{isSingle:!1,isAuto:j,isRight:oe,css:ie,isGradientButtonBorder:"gradient"===K.color&&(z||q),children:te}),(0,h.jsx)("div",{className:(0,f.Z)("nextui-button-text",{"nextui-button-text-right":oe,"nextui-button-text-left":!oe}),children:F})]}):(0,h.jsx)("span",{className:"nextui-button-text",children:F}),(0,h.jsx)(b.Z,{color:"white",...ee})]})}));P.Ts&&(N.displayName="NextUI.Button"),N.toString=()=>".nextui-button";var E=(0,$.Z)(N,{ghost:!1,bordered:!1,ripple:!0,animated:!0,disabled:!1,autoFocus:!1,auto:!1,className:"",type:"button"});var L=(0,g.zo)("div",{display:"inline-flex",margin:"$3",backgroundColor:"transparent",height:"min-content",[`& ${C}`]:{".nextui-button-text":{top:0}},variants:{vertical:{true:{fd:"column",[`& ${C}`]:{"&:not(:first-child)":{btlr:0,btrr:0},"&:not(:last-child)":{bblr:0,bbrr:0}}},false:{fd:"row",[`& ${C}`]:{"&:not(:first-child)":{btlr:0,bblr:0},"&:not(:last-child)":{btrr:0,bbrr:0}}}},size:{xs:{br:"$xs"},sm:{br:"$sm"},md:{br:"$md"},lg:{br:"$base"},xl:{br:"$xl"}},rounded:{true:{br:"$pill"}},bordered:{true:{bg:"transparent"}},gradient:{true:{pl:0}}},defaultVariants:{vertical:!1},compoundVariants:[{bordered:!0,vertical:!0,css:{[`& ${C}`]:{"&:not(:last-child)":{borderBottom:"none",paddingBottom:"0"}}}},{bordered:!0,vertical:!1,css:{[`& ${C}`]:{"&:not(:first-child)":{borderLeft:"none"}}}},{bordered:!0,vertical:!1,gradient:!0,css:{[`& ${C}`]:{"&:not(:last-child)&:not(:first-child)":{pl:0},"&:last-child":{pl:0}}}}]});const F=e=>{const{disabled:t,size:r,color:n,bordered:i,ghost:s,light:a,flat:l,shadow:c,auto:d,animated:u,rounded:b,ripple:g,borderWeight:$,children:f,...m}=e,x=(0,o.useMemo)((()=>({disabled:t,size:r,color:n,bordered:i,light:a,ghost:s,flat:l,shadow:c,auto:d,borderWeight:$,animated:u,rounded:b,ripple:g,isButtonGroup:!0})),[t,u,r,g,n,i,a,s,l,$]);return(0,h.jsx)(p.Provider,{value:x,children:(0,h.jsx)(L,{size:r,bordered:i||s,gradient:"gradient"===e.color,...m,children:f})})};F.toString=()=>".nextui-button-group";const R=o.memo(F);var W=(0,$.Z)(R,{borderWeight:"normal",size:"md",color:"default"});E.Group=W;var B=E},5208:function(e,t,r){"use strict";r.d(t,{ZP:function(){return f}});var o,n,i=r(7294),s=r(88),a=r(6212),l=r(3917);const c=(0,a.zo)("svg",{ml:"$1",as:"center",display:"inline-flex",color:"currentColor"});var d=(0,a.zo)("a",{display:"inline-flex",alignItems:"baseline",lineHeight:"inherit",textDecoration:"none",width:"fitContent",backgroundImage:"inherit",backgroundColor:"inherit",backgroundClip:"inherit",WebkitTextFillColor:"inherit","&:hover":{opacity:.8},"@motion":{transition:"none"},variants:{color:{default:{color:"$link"},text:{color:"$text"},primary:{color:"$primary"},secondary:{color:"$secondary"},success:{color:"$success"},warning:{color:"$warning"},error:{color:"$error"}},underline:{true:{"&:hover, &:active, &:focus":{textDecoration:"underline"}}},block:{true:{padding:"$2 $4",borderRadius:"$base"}},animated:{true:{transition:"$link"}}},compoundVariants:[{color:"default",block:!0,css:{"&:hover":{backgroundColor:(0,l.jK)(null==(o=a.rS.colors)||null==(n=o.link)?void 0:n.value,.2)}}},{color:"primary",block:!0,css:{"&:hover":{backgroundColor:"$primaryLight"}}},{color:"secondary",block:!0,css:{"&:hover":{backgroundColor:"$secondaryLight"}}},{color:"success",block:!0,css:{"&:hover":{backgroundColor:"$successLight"}}},{color:"warning",block:!0,css:{"&:hover":{backgroundColor:"$warningLight"}}},{color:"error",block:!0,css:{"&:hover":{backgroundColor:"$errorLight"}}}],defaultVariants:{color:"default",animated:!0}}),u=r(5893);const b=()=>(0,u.jsxs)(c,{viewBox:"0 0 24 24",width:"1em",height:"1em",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round",fill:"none",shapeRendering:"geometricPrecision",className:"nextui-link-icon",children:[(0,u.jsx)("path",{d:"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"}),(0,u.jsx)("path",{d:"M15 3h6v6"}),(0,u.jsx)("path",{d:"M10 14L21 3"})]});b.toString=()=>".nextui-link-icon";var p=i.memo(b),g=r(3569);const $=i.forwardRef((({children:e,icon:t,...r},o)=>(0,u.jsx)(d,{...r,ref:o,children:(0,u.jsxs)(u.Fragment,{children:[e,t&&(0,u.jsx)(p,{})]})})));g.Ts&&($.displayName="NextUI.Link"),$.toString=()=>".nextui-link";var f=(0,s.Z)($,{icon:!1})},9975:function(e,t,r){"use strict";r.d(t,{BM:function(){return n},Oe:function(){return s},UU:function(){return i}});var o=r(6212);(0,o.iv)({WebkitTapHighlightColor:"transparent","&:focus:not(&:focus-visible)":{boxShadow:"none"},"&:focus":{outline:"none",boxShadow:"0 0 0 2px $colors$background, 0 0 0 4px $colors$primary"},"@safari":{WebkitTapHighlightColor:"transparent",outline:"none"}});const n=(0,o.iv)({variants:{isFocusVisible:{true:{outline:"transparent solid 2px",outlineOffset:"2px",boxShadow:"0 0 0 2px $colors$background, 0 0 0 4px $colors$primary"},false:{outline:"none"}}}}),i=(0,o.iv)({transform:"translateZ(0)",backfaceVisibility:"hidden"}),s=((0,o.iv)({border:"0px",clip:"rect(0px, 0px, 0px, 0px)",height:"1px",width:"1px",margin:"-1px",padding:"0px",overflow:"hidden",whiteSpace:"nowrap",position:"absolute"}),(0,o.iv)({'&[aria-haspopup="true"]&[aria-expanded="true"]':{opacity:.7,transform:"scale(0.97)"}}))},9260:function(e,t,r){"use strict";r.d(t,{Z:function(){return n}});var o=r(7294),n=(e=!1,t)=>{const[r,n]=(0,o.useState)(e),[i,s]=(0,o.useState)(0),[a,l]=(0,o.useState)(0);return{visible:r,x:i,y:a,onClick:e=>{if(!t.current)return;const r=t.current.getBoundingClientRect();n(!0),s(e.clientX-r.left),l(e.clientY-r.top)},onCompleted:()=>{n(!1),s(0),l(0)}}}},3569:function(e,t,r){"use strict";r.d(t,{Ts:function(){return o}});const o=!1},3917:function(e,t,r){"use strict";r.d(t,{jK:function(){return c},h1:function(){return a}});const o=(...e)=>e;o("xs","sm","md","lg","xl");const n=o("default","primary","secondary","success","warning","error","gradient");o("default","primary","secondary","success","warning","error"),o("default","primary","secondary","success","warning","error","invert","gradient"),o("default","primary","secondary","success","warning","error","invert"),o("default","primary","secondary","success","warning","error","dark","lite","alert","purple","violet","gradient","cyan"),o("default","points","points-opacity","gradient","spinner"),o("light","normal","bold","extrabold","black"),o("normal","bold","lighter","bolder","inherit","initial","revert","unset"),o("none","capitalize","uppercase","lowercase","full-width","full-size-kana","inherit","initial","revert","unset");o("default","slient","prevent"),o("hover","click"),o("top","topStart","topEnd","left","leftStart","leftEnd","bottom","bottomStart","bottomEnd","right","rightStart","rightEnd"),o("static","relative","absolute","fixed","sticky","inherit","initial","revert","unset"),o("contain","cover","fill","none","scale-down","inherit","initial","revert","unset"),o("start","center","end","left","right"),o("flex-start","center","flex-end","space-between","space-around","space-evenly"),o("flex-start","flex-end","center","stretch","baseline"),o("stretch","center","flex-start","flex-end","space-between","space-around"),o("row","row-reverse","column","column-reverse"),o("nowrap","wrap","wrap-reverse"),o("flex","block","grid","inline","inline-block","inline-flex","inline-grid"),o("left","right"),o("start","center","end");o("clearable","as","rounded","labelLeft","labelRight","contentLeft","contentRight","contentClickable","contentLeftStyling","contentRightStyling","onContentClick","onClearClick","css"),o("items","disabledKeys","allowDuplicateSelectionEvents","disallowEmptySelection","defaultSelectedKeys","sortDescriptor","onSortChange");o("toggle","replace"),o("none","single","multiple"),o("flat","light","solid","shadow"),o("flat","bordered","shadow");const i=e=>{if("undefined"!=typeof document||!e){const t=s(e)?e.replace("var(","").replace(")",""):`--${e}`;return getComputedStyle(document.documentElement).getPropertyValue(t)}return""},s=e=>!(!e||0!==(null==e?void 0:e.indexOf("var("))),a=e=>null!=n.find((t=>t===e)),l=e=>{const t=s(e)?i(e):e;if("#"===t.charAt(0))return(e=>{const t=e.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,((e,t,r,o)=>`${t}${t}${r}${r}${o}${o}`)),r=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);if(!r)throw new Error(`Next UI: Unsupported ${e} color.`);return[Number.parseInt(r[1],16),Number.parseInt(r[2],16),Number.parseInt(r[3],16)]})(t);const r=t.replace(/ /g,""),o=t.substr(0,4),n=r.match(/\((.+)\)/);if(!o.startsWith("rgb")||!n)throw new Error('Next UI: Only support ["RGB", "RGBA", "HEX"] color.');return n[1].split(",").map((e=>Number.parseFloat(e)))},c=(e,t=1)=>{if(!e)return"";const r=s(e)?i(e):e;if(/#[a-fA-F0-9]{3,6}/g.test(r))return((e,t=1)=>{let r=0,o=0,n=0;return 4==e.length?(r="0x"+e[1]+e[1],o="0x"+e[2]+e[2],n="0x"+e[3]+e[3]):7==e.length&&(r="0x"+e[1]+e[2],o="0x"+e[3]+e[4],n="0x"+e[5]+e[6]),`rgba(${+r}, ${+o},${+n},${t})`})(r,t);if(!/^#|rgb|RGB/.test(r))return r;const[o,n,a]=l(r);return`rgba(${o}, ${n}, ${a}, ${t>1?1:t<0?0:t})`}},6772:function(e,t,r){"use strict";r.d(t,{m:function(){return o}});const o=e=>`calc(${15.25*e}pt + 1px * ${e-1})`},2903:function(e,t,r){"use strict";r.d(t,{gy:function(){return n}});var o=r(7294);"undefined"==typeof window||!window.document||window.document.createElement;function n(e){const t=(0,o.useRef)(null);return(0,o.useImperativeHandle)(e,(()=>t.current)),t}},8375:function(e,t,r){"use strict";r.d(t,{q:function(){return c}});var o=r(7294),n=r(6212),i=r(88),s=r(1309),a=r(5893);const l=(0,n.F4)({"0%":{opacity:0,transform:"scale(0.25)"},"30%":{opacity:1},"80%":{opacity:.5},"100%":{transform:"scale(28)",opacity:0}}),c=(0,n.zo)("div",{position:"absolute",left:0,right:0,top:0,bottom:0,"& svg":{position:"absolute",animation:`350ms linear ${l}`,animationFillMode:"forwards",width:"$md",height:"$md"}}),d=o.memo((({visible:e,x:t,y:r,color:n,onCompleted:i,className:l,...d})=>{const u=(0,o.useRef)(null),b=Number.isNaN(+r)?0:r-10,p=Number.isNaN(+t)?0:t-10;return(0,o.useEffect)((()=>{if(u.current)return u.current.addEventListener("animationend",i),()=>{u.current&&u.current.removeEventListener("animationend",i)}})),e?(0,a.jsx)(c,{ref:u,className:(0,s.Z)("nextui-drip",l),...d,children:(0,a.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",style:{top:b,left:p},children:(0,a.jsx)("g",{stroke:"none",strokeWidth:"1",fill:"none",fillRule:"evenodd",children:(0,a.jsx)("g",{className:"nextui-drip-filler",fill:n,children:(0,a.jsx)("rect",{width:"100%",height:"100%",rx:"10"})})})})}):null}));t.Z=(0,i.Z)(d,{visible:!1,x:0,y:0,className:""})},9641:function(e,t,r){"use strict";r.d(t,{Fx:function(){return E},kc:function(){return H}});var o=r(7294),n=r(4213),i=r(7354),s=r(6010);function a(e,t,r,o){Object.defineProperty(e,t,{get:r,set:o,enumerable:!0,configurable:!0})}var l={};a(l,"FocusScope",(()=>g)),a(l,"useFocusManager",(()=>$)),a(l,"getFocusableTreeWalker",(()=>k)),a(l,"createFocusManager",(()=>P));function c(e){if("virtual"===(0,i.Jz)()){let t=document.activeElement;(0,n.QB)((()=>{document.activeElement===t&&document.contains(e)&&(0,n.Ao)(e)}))}else(0,n.Ao)(e)}function d(e,t){return"#comment"!==e.nodeName&&function(e){if(!(e instanceof HTMLElement)&&!(e instanceof SVGElement))return!1;let{display:t,visibility:r}=e.style,o="none"!==t&&"hidden"!==r&&"collapse"!==r;if(o){const{getComputedStyle:t}=e.ownerDocument.defaultView;let{display:r,visibility:n}=t(e);o="none"!==r&&"hidden"!==n&&"collapse"!==n}return o}(e)&&function(e,t){return!e.hasAttribute("hidden")&&("DETAILS"!==e.nodeName||!t||"SUMMARY"===t.nodeName||e.hasAttribute("open"))}(e,t)&&(!e.parentElement||d(e.parentElement,e))}a({},"focusSafely",(()=>c));const u=o.createContext(null);let b=null,p=new Map;function g(e){let{children:t,contain:r,restoreFocus:i,autoFocus:s}=e,a=(0,o.useRef)(),l=(0,o.useRef)(),c=(0,o.useRef)([]),d=(0,o.useContext)(u),g=null===d||void 0===d?void 0:d.scopeRef;(0,n.bt)((()=>{let e=a.current.nextSibling,t=[];for(;e&&e!==l.current;)t.push(e),e=e.nextSibling;c.current=t}),[t,g]),(0,n.bt)((()=>(p.set(c,g),()=>{c!==b&&!w(c,b)||g&&!p.has(g)||(b=g),p.delete(c)})),[c,g]),function(e,t){let r=(0,o.useRef)(),i=(0,o.useRef)(null);(0,n.bt)((()=>{let o=e.current;if(!t)return;let n=t=>{if("Tab"!==t.key||t.altKey||t.ctrlKey||t.metaKey||e!==b)return;let r=document.activeElement,o=e.current;if(!v(r,o))return;let n=k(x(o),{tabbable:!0},o);n.currentNode=r;let i=t.shiftKey?n.previousNode():n.nextNode();i||(n.currentNode=t.shiftKey?o[o.length-1].nextElementSibling:o[0].previousElementSibling,i=t.shiftKey?n.previousNode():n.nextNode()),t.preventDefault(),i&&S(i,!0)},s=t=>{!b||w(b,e)?(b=e,r.current=t.target):e!==b||y(t.target,e)?e===b&&(r.current=t.target):r.current?r.current.focus():b&&C(b.current)},a=t=>{i.current=requestAnimationFrame((()=>{e!==b||y(document.activeElement,e)||(b=e,r.current=t.target,r.current.focus())}))};return document.addEventListener("keydown",n,!1),document.addEventListener("focusin",s,!1),o.forEach((e=>e.addEventListener("focusin",s,!1))),o.forEach((e=>e.addEventListener("focusout",a,!1))),()=>{document.removeEventListener("keydown",n,!1),document.removeEventListener("focusin",s,!1),o.forEach((e=>e.removeEventListener("focusin",s,!1))),o.forEach((e=>e.removeEventListener("focusout",a,!1)))}}),[e,t]),(0,o.useEffect)((()=>()=>cancelAnimationFrame(i.current)),[i])}(c,r),function(e,t,r){const i=(0,o.useRef)("undefined"!==typeof document?document.activeElement:null);(0,n.bt)((()=>{let o=i.current;if(!t)return;let n=t=>{if("Tab"!==t.key||t.altKey||t.ctrlKey||t.metaKey)return;let r=document.activeElement;if(!v(r,e.current))return;let n=k(document.body,{tabbable:!0});n.currentNode=r;let i=t.shiftKey?n.previousNode():n.nextNode();if(document.body.contains(o)&&o!==document.body||(o=null),(!i||!v(i,e.current))&&o){n.currentNode=o;do{i=t.shiftKey?n.previousNode():n.nextNode()}while(v(i,e.current));t.preventDefault(),t.stopPropagation(),i?S(i,!0):!function(e){for(let t of p.keys())if(v(e,t.current))return!0;return!1}(o)?r.blur():S(o,!0)}};return r||document.addEventListener("keydown",n,!0),()=>{r||document.removeEventListener("keydown",n,!0),t&&o&&v(document.activeElement,e.current)&&requestAnimationFrame((()=>{document.body.contains(o)&&S(o)}))}}),[e,t,r])}(c,i,r),function(e,t){const r=o.useRef(t);(0,o.useEffect)((()=>{r.current&&(b=e,v(document.activeElement,b.current)||C(e.current)),r.current=!1}),[])}(c,s);let $=function(e){return{focusNext(t={}){let r=e.current,{from:o,tabbable:n,wrap:i}=t,s=o||document.activeElement,a=r[0].previousElementSibling,l=k(x(r),{tabbable:n},r);l.currentNode=v(s,r)?s:a;let c=l.nextNode();return!c&&i&&(l.currentNode=a,c=l.nextNode()),c&&S(c,!0),c},focusPrevious(t={}){let r=e.current,{from:o,tabbable:n,wrap:i}=t,s=o||document.activeElement,a=r[r.length-1].nextElementSibling,l=k(x(r),{tabbable:n},r);l.currentNode=v(s,r)?s:a;let c=l.previousNode();return!c&&i&&(l.currentNode=a,c=l.previousNode()),c&&S(c,!0),c},focusFirst(t={}){let r=e.current,{tabbable:o}=t,n=k(x(r),{tabbable:o},r);n.currentNode=r[0].previousElementSibling;let i=n.nextNode();return i&&S(i,!0),i},focusLast(t={}){let r=e.current,{tabbable:o}=t,n=k(x(r),{tabbable:o},r);n.currentNode=r[r.length-1].nextElementSibling;let i=n.previousNode();return i&&S(i,!0),i}}}(c);return o.createElement(u.Provider,{value:{scopeRef:c,focusManager:$}},o.createElement("span",{"data-focus-scope-start":!0,hidden:!0,ref:a}),t,o.createElement("span",{"data-focus-scope-end":!0,hidden:!0,ref:l}))}function $(){var e;return null===(e=(0,o.useContext)(u))||void 0===e?void 0:e.focusManager}const f=["input:not([disabled]):not([type=hidden])","select:not([disabled])","textarea:not([disabled])","button:not([disabled])","a[href]","area[href]","summary","iframe","object","embed","audio[controls]","video[controls]","[contenteditable]"],h=f.join(":not([hidden]),")+",[tabindex]:not([disabled]):not([hidden])";f.push('[tabindex]:not([tabindex="-1"]):not([disabled])');const m=f.join(':not([hidden]):not([tabindex="-1"]),');function x(e){return e[0].parentElement}function v(e,t){return t.some((t=>t.contains(e)))}function y(e,t){for(let r of p.keys())if((r===t||w(t,r))&&v(e,r.current))return!0;return!1}function w(e,t){let r=p.get(t);return!!r&&(r===e||w(e,r))}function S(e,t=!1){if(null==e||t){if(null!=e)try{e.focus()}catch(r){}}else try{c(e)}catch(o){}}function C(e){let t=e[0].previousElementSibling,r=k(x(e),{tabbable:!0},e);r.currentNode=t,S(r.nextNode())}function k(e,t,r){let o=(null===t||void 0===t?void 0:t.tabbable)?m:h,n=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,{acceptNode(e){var n;return(null===t||void 0===t||null===(n=t.from)||void 0===n?void 0:n.contains(e))?NodeFilter.FILTER_REJECT:!e.matches(o)||!d(e)||r&&!v(e,r)||(null===t||void 0===t?void 0:t.accept)&&!t.accept(e)?NodeFilter.FILTER_SKIP:NodeFilter.FILTER_ACCEPT}});return(null===t||void 0===t?void 0:t.from)&&(n.currentNode=t.from),n}function P(e,t={}){return{focusNext(r={}){let o=e.current,{from:n,tabbable:i=t.tabbable,wrap:s=t.wrap,accept:a=t.accept}=r,l=n||document.activeElement,c=k(o,{tabbable:i,accept:a});o.contains(l)&&(c.currentNode=l);let d=c.nextNode();return!d&&s&&(c.currentNode=o,d=c.nextNode()),d&&S(d,!0),d},focusPrevious(r=t){let o=e.current,{from:n,tabbable:i=t.tabbable,wrap:s=t.wrap,accept:a=t.accept}=r,l=n||document.activeElement,c=k(o,{tabbable:i,accept:a});if(!o.contains(l)){let e=N(c);return e&&S(e,!0),e}c.currentNode=l;let d=c.previousNode();return!d&&s&&(c.currentNode=o,d=N(c)),d&&S(d,!0),d},focusFirst(r=t){let o=e.current,{tabbable:n=t.tabbable,accept:i=t.accept}=r,s=k(o,{tabbable:n,accept:i}).nextNode();return s&&S(s,!0),s},focusLast(r=t){let o=e.current,{tabbable:n=t.tabbable,accept:i=t.accept}=r,s=N(k(o,{tabbable:n,accept:i}));return s&&S(s,!0),s}}}function N(e){let t,r;do{r=e.lastChild(),r&&(t=r)}while(r);return t}a({},"FocusRing",(()=>L));function E(e={}){let{autoFocus:t=!1,isTextInput:r,within:n}=e,s=(0,o.useRef)({isFocused:!1,isFocusVisible:t||(0,i.E)()}),[a,l]=(0,o.useState)(!1),[c,d]=(0,o.useState)((()=>s.current.isFocused&&s.current.isFocusVisible)),u=(0,o.useCallback)((()=>d(s.current.isFocused&&s.current.isFocusVisible)),[]),b=(0,o.useCallback)((e=>{s.current.isFocused=e,l(e),u()}),[u]);(0,i.mG)((e=>{s.current.isFocusVisible=e,u()}),[],{isTextInput:r});let{focusProps:p}=(0,i.KK)({isDisabled:n,onFocusChange:b}),{focusWithinProps:g}=(0,i.L_)({isDisabled:!n,onFocusWithinChange:b});return{isFocused:a,isFocusVisible:s.current.isFocused&&c,focusProps:n?g:p}}function L(e){let{children:t,focusClass:r,focusRingClass:i}=e,{isFocused:a,isFocusVisible:l,focusProps:c}=E(e),d=o.Children.only(t);return o.cloneElement(d,(0,n.dG)(d.props,{...c,className:(0,s.Z)({[r||""]:a,[i||""]:l})}))}a({},"useFocusRing",(()=>E));var F={};a(F,"FocusableProvider",(()=>B)),a(F,"useFocusable",(()=>H));let R=o.createContext(null);function W(e,t){let{children:r,...n}=e,i={...n,ref:t};return o.createElement(R.Provider,{value:i},r)}let B=o.forwardRef(W);function H(e,t){let{focusProps:r}=(0,i.KK)(e),{keyboardProps:s}=(0,i.v5)(e),a=(0,n.dG)(r,s),l=function(e){let t=(0,o.useContext)(R)||{};(0,n.lE)(t,e);let{ref:r,...i}=t;return i}(t),d=e.isDisabled?{}:l,u=(0,o.useRef)(e.autoFocus);return(0,o.useEffect)((()=>{u.current&&t.current&&c(t.current),u.current=!1}),[t]),{focusableProps:(0,n.dG)({...a,tabIndex:e.excludeFromTabOrder&&!e.isDisabled?-1:void 0},d)}}},9008:function(e,t,r){e.exports=r(5443)}}]); \ No newline at end of file diff --git a/dashboard/out/_next/static/chunks/732-e52c1d2253f458fa.js b/dashboard/out/_next/static/chunks/732-e52c1d2253f458fa.js new file mode 100644 index 0000000..964ceae --- /dev/null +++ b/dashboard/out/_next/static/chunks/732-e52c1d2253f458fa.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[732],{5446:function(e,t,r){var n=r(5784),o=r(5893);t.Z=(0,n.Z)((0,o.jsx)("path",{d:"M12 5v8.55c-.94-.54-2.1-.75-3.33-.32-1.34.48-2.37 1.67-2.61 3.07-.46 2.74 1.86 5.08 4.59 4.65 1.96-.31 3.35-2.11 3.35-4.1V7h2c1.1 0 2-.9 2-2s-.9-2-2-2h-2c-1.1 0-2 .9-2 2z"}),"AudiotrackRounded")},5784:function(e,t,r){r.d(t,{Z:function(){return $n}});var n=r(7462),o=r(7294),i=r.t(o,2);function a(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n=0||(o[r]=e[r]);return o}var s=r(6010);function c(e){let t="https://mui.com/production-error/?code="+e;for(let r=1;r{void 0===r[t]&&(r[t]=e[t])})),r}(t.components[r].defaultProps,o):o}function p(e){return null!==e&&"object"===typeof e&&e.constructor===Object}function f(e,t,r={clone:!0}){const o=r.clone?(0,n.Z)({},e):e;return p(e)&&p(t)&&Object.keys(t).forEach((n=>{"__proto__"!==n&&(p(t[n])&&n in e&&p(e[n])?o[n]=f(e[n],t[n],r):o[n]=t[n])})),o}const h=["values","unit","step"];function m(e){const{values:t={xs:0,sm:600,md:900,lg:1200,xl:1536},unit:r="px",step:o=5}=e,i=a(e,h),s=(e=>{const t=Object.keys(e).map((t=>({key:t,val:e[t]})))||[];return t.sort(((e,t)=>e.val-t.val)),t.reduce(((e,t)=>(0,n.Z)({},e,{[t.key]:t.val})),{})})(t),c=Object.keys(s);function l(e){return`@media (min-width:${"number"===typeof t[e]?t[e]:e}${r})`}function u(e){return`@media (max-width:${("number"===typeof t[e]?t[e]:e)-o/100}${r})`}function d(e,n){const i=c.indexOf(n);return`@media (min-width:${"number"===typeof t[e]?t[e]:e}${r}) and (max-width:${(-1!==i&&"number"===typeof t[c[i]]?t[c[i]]:n)-o/100}${r})`}return(0,n.Z)({keys:c,values:s,up:l,down:u,between:d,only:function(e){return c.indexOf(e)+1`@media (min-width:${b[e]}px)`};function v(e,t,r){const n=e.theme||{};if(Array.isArray(t)){const e=n.breakpoints||y;return t.reduce(((n,o,i)=>(n[e.up(e.keys[i])]=r(t[i]),n)),{})}if("object"===typeof t){const e=n.breakpoints||y;return Object.keys(t).reduce(((n,o)=>{if(-1!==Object.keys(e.values||b).indexOf(o)){n[e.up(o)]=r(t[o],o)}else{const e=o;n[e]=t[e]}return n}),{})}return r(t)}function x(e={}){var t;return(null==(t=e.keys)?void 0:t.reduce(((t,r)=>(t[e.up(r)]={},t)),{}))||{}}function k(e,t){return e.reduce(((e,t)=>{const r=e[t];return(!r||0===Object.keys(r).length)&&delete e[t],e}),t)}function w(e,t,r=!0){if(!t||"string"!==typeof t)return null;if(e&&e.vars&&r){const r=`vars.${t}`.split(".").reduce(((e,t)=>e&&e[t]?e[t]:null),e);if(null!=r)return r}return t.split(".").reduce(((e,t)=>e&&null!=e[t]?e[t]:null),e)}function $(e,t,r,n=r){let o;return o="function"===typeof e?e(r):Array.isArray(e)?e[r]||n:w(e,r)||n,t&&(o=t(o,n)),o}var S=function(e){const{prop:t,cssProperty:r=e.prop,themeKey:n,transform:o}=e,i=e=>{if(null==e[t])return null;const i=e[t],a=w(e.theme,n)||{};return v(e,i,(e=>{let n=$(a,o,e);return e===n&&"string"===typeof e&&(n=$(a,o,`${t}${"default"===e?"":l(e)}`,e)),!1===r?n:{[r]:n}}))};return i.propTypes={},i.filterProps=[t],i};var A=function(e,t){return t?f(e,t,{clone:!1}):e};const C={m:"margin",p:"padding"},P={t:"Top",r:"Right",b:"Bottom",l:"Left",x:["Left","Right"],y:["Top","Bottom"]},O={marginX:"mx",marginY:"my",paddingX:"px",paddingY:"py"},z=function(e){const t={};return r=>(void 0===t[r]&&(t[r]=e(r)),t[r])}((e=>{if(e.length>2){if(!O[e])return[e];e=O[e]}const[t,r]=e.split(""),n=C[t],o=P[r]||"";return Array.isArray(o)?o.map((e=>n+e)):[n+o]})),T=["m","mt","mr","mb","ml","mx","my","margin","marginTop","marginRight","marginBottom","marginLeft","marginX","marginY","marginInline","marginInlineStart","marginInlineEnd","marginBlock","marginBlockStart","marginBlockEnd"],R=["p","pt","pr","pb","pl","px","py","padding","paddingTop","paddingRight","paddingBottom","paddingLeft","paddingX","paddingY","paddingInline","paddingInlineStart","paddingInlineEnd","paddingBlock","paddingBlockStart","paddingBlockEnd"],_=[...T,...R];function j(e,t,r,n){var o;const i=null!=(o=w(e,t,!1))?o:r;return"number"===typeof i?e=>"string"===typeof e?e:i*e:Array.isArray(i)?e=>"string"===typeof e?e:i[e]:"function"===typeof i?i:()=>{}}function E(e){return j(e,"spacing",8)}function I(e,t){if("string"===typeof t||null==t)return t;const r=e(Math.abs(t));return t>=0?r:"number"===typeof r?-r:`-${r}`}function M(e,t,r,n){if(-1===t.indexOf(r))return null;const o=function(e,t){return r=>e.reduce(((e,n)=>(e[n]=I(t,r),e)),{})}(z(r),n);return v(e,e[r],o)}function W(e,t){const r=E(e.theme);return Object.keys(e).map((n=>M(e,t,n,r))).reduce(A,{})}function N(e){return W(e,T)}function Z(e){return W(e,R)}function F(e){return W(e,_)}N.propTypes={},N.filterProps=T,Z.propTypes={},Z.filterProps=R,F.propTypes={},F.filterProps=_;var B=F;const H=["breakpoints","palette","spacing","shape"];var L=function(e={},...t){const{breakpoints:r={},palette:o={},spacing:i,shape:s={}}=e,c=a(e,H),l=m(r),u=function(e=8){if(e.mui)return e;const t=E({spacing:e}),r=(...e)=>(0===e.length?[1]:e).map((e=>{const r=t(e);return"number"===typeof r?`${r}px`:r})).join(" ");return r.mui=!0,r}(i);let d=f({breakpoints:l,direction:"ltr",components:{},palette:(0,n.Z)({mode:"light"},o),spacing:u,shape:(0,n.Z)({},g,s)},c);return d=t.reduce(((e,t)=>f(e,t)),d),d};var G=o.createContext(null);var K=function(e=null){const t=o.useContext(G);return t&&(r=t,0!==Object.keys(r).length)?t:e;var r};const V=L();var U=function(e=V){return K(e)};function D(e,t){return(0,n.Z)({toolbar:{minHeight:56,[e.up("xs")]:{"@media (orientation: landscape)":{minHeight:48}},[e.up("sm")]:{minHeight:64}}},t)}function q(e,t=0,r=1){return Math.min(Math.max(t,e),r)}function X(e){if(e.type)return e;if("#"===e.charAt(0))return X(function(e){e=e.slice(1);const t=new RegExp(`.{1,${e.length>=6?2:1}}`,"g");let r=e.match(t);return r&&1===r[0].length&&(r=r.map((e=>e+e))),r?`rgb${4===r.length?"a":""}(${r.map(((e,t)=>t<3?parseInt(e,16):Math.round(parseInt(e,16)/255*1e3)/1e3)).join(", ")})`:""}(e));const t=e.indexOf("("),r=e.substring(0,t);if(-1===["rgb","rgba","hsl","hsla","color"].indexOf(r))throw new Error(c(9,e));let n,o=e.substring(t+1,e.length-1);if("color"===r){if(o=o.split(" "),n=o.shift(),4===o.length&&"/"===o[3].charAt(0)&&(o[3]=o[3].slice(1)),-1===["srgb","display-p3","a98-rgb","prophoto-rgb","rec-2020"].indexOf(n))throw new Error(c(10,n))}else o=o.split(",");return o=o.map((e=>parseFloat(e))),{type:r,values:o,colorSpace:n}}function Y(e){const{type:t,colorSpace:r}=e;let{values:n}=e;return-1!==t.indexOf("rgb")?n=n.map(((e,t)=>t<3?parseInt(e,10):e)):-1!==t.indexOf("hsl")&&(n[1]=`${n[1]}%`,n[2]=`${n[2]}%`),n=-1!==t.indexOf("color")?`${r} ${n.join(" ")}`:`${n.join(", ")}`,`${t}(${n})`}function J(e){let t="hsl"===(e=X(e)).type||"hsla"===e.type?X(function(e){e=X(e);const{values:t}=e,r=t[0],n=t[1]/100,o=t[2]/100,i=n*Math.min(o,1-o),a=(e,t=(e+r/30)%12)=>o-i*Math.max(Math.min(t-3,9-t,1),-1);let s="rgb";const c=[Math.round(255*a(0)),Math.round(255*a(8)),Math.round(255*a(4))];return"hsla"===e.type&&(s+="a",c.push(t[3])),Y({type:s,values:c})}(e)).values:e.values;return t=t.map((t=>("color"!==e.type&&(t/=255),t<=.03928?t/12.92:((t+.055)/1.055)**2.4))),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function Q(e,t){if(e=X(e),t=q(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb")||-1!==e.type.indexOf("color"))for(let r=0;r<3;r+=1)e.values[r]*=1-t;return Y(e)}function ee(e,t){if(e=X(e),t=q(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(let r=0;r<3;r+=1)e.values[r]+=(255-e.values[r])*t;else if(-1!==e.type.indexOf("color"))for(let r=0;r<3;r+=1)e.values[r]+=(1-e.values[r])*t;return Y(e)}var te={black:"#000",white:"#fff"};var re={50:"#fafafa",100:"#f5f5f5",200:"#eeeeee",300:"#e0e0e0",400:"#bdbdbd",500:"#9e9e9e",600:"#757575",700:"#616161",800:"#424242",900:"#212121",A100:"#f5f5f5",A200:"#eeeeee",A400:"#bdbdbd",A700:"#616161"};var ne={50:"#f3e5f5",100:"#e1bee7",200:"#ce93d8",300:"#ba68c8",400:"#ab47bc",500:"#9c27b0",600:"#8e24aa",700:"#7b1fa2",800:"#6a1b9a",900:"#4a148c",A100:"#ea80fc",A200:"#e040fb",A400:"#d500f9",A700:"#aa00ff"};var oe={50:"#ffebee",100:"#ffcdd2",200:"#ef9a9a",300:"#e57373",400:"#ef5350",500:"#f44336",600:"#e53935",700:"#d32f2f",800:"#c62828",900:"#b71c1c",A100:"#ff8a80",A200:"#ff5252",A400:"#ff1744",A700:"#d50000"};var ie={50:"#fff3e0",100:"#ffe0b2",200:"#ffcc80",300:"#ffb74d",400:"#ffa726",500:"#ff9800",600:"#fb8c00",700:"#f57c00",800:"#ef6c00",900:"#e65100",A100:"#ffd180",A200:"#ffab40",A400:"#ff9100",A700:"#ff6d00"};var ae={50:"#e3f2fd",100:"#bbdefb",200:"#90caf9",300:"#64b5f6",400:"#42a5f5",500:"#2196f3",600:"#1e88e5",700:"#1976d2",800:"#1565c0",900:"#0d47a1",A100:"#82b1ff",A200:"#448aff",A400:"#2979ff",A700:"#2962ff"};var se={50:"#e1f5fe",100:"#b3e5fc",200:"#81d4fa",300:"#4fc3f7",400:"#29b6f6",500:"#03a9f4",600:"#039be5",700:"#0288d1",800:"#0277bd",900:"#01579b",A100:"#80d8ff",A200:"#40c4ff",A400:"#00b0ff",A700:"#0091ea"};var ce={50:"#e8f5e9",100:"#c8e6c9",200:"#a5d6a7",300:"#81c784",400:"#66bb6a",500:"#4caf50",600:"#43a047",700:"#388e3c",800:"#2e7d32",900:"#1b5e20",A100:"#b9f6ca",A200:"#69f0ae",A400:"#00e676",A700:"#00c853"};const le=["mode","contrastThreshold","tonalOffset"],ue={text:{primary:"rgba(0, 0, 0, 0.87)",secondary:"rgba(0, 0, 0, 0.6)",disabled:"rgba(0, 0, 0, 0.38)"},divider:"rgba(0, 0, 0, 0.12)",background:{paper:te.white,default:te.white},action:{active:"rgba(0, 0, 0, 0.54)",hover:"rgba(0, 0, 0, 0.04)",hoverOpacity:.04,selected:"rgba(0, 0, 0, 0.08)",selectedOpacity:.08,disabled:"rgba(0, 0, 0, 0.26)",disabledBackground:"rgba(0, 0, 0, 0.12)",disabledOpacity:.38,focus:"rgba(0, 0, 0, 0.12)",focusOpacity:.12,activatedOpacity:.12}},de={text:{primary:te.white,secondary:"rgba(255, 255, 255, 0.7)",disabled:"rgba(255, 255, 255, 0.5)",icon:"rgba(255, 255, 255, 0.5)"},divider:"rgba(255, 255, 255, 0.12)",background:{paper:"#121212",default:"#121212"},action:{active:te.white,hover:"rgba(255, 255, 255, 0.08)",hoverOpacity:.08,selected:"rgba(255, 255, 255, 0.16)",selectedOpacity:.16,disabled:"rgba(255, 255, 255, 0.3)",disabledBackground:"rgba(255, 255, 255, 0.12)",disabledOpacity:.38,focus:"rgba(255, 255, 255, 0.12)",focusOpacity:.12,activatedOpacity:.24}};function pe(e,t,r,n){const o=n.light||n,i=n.dark||1.5*n;e[t]||(e.hasOwnProperty(r)?e[t]=e[r]:"light"===t?e.light=ee(e.main,o):"dark"===t&&(e.dark=Q(e.main,i)))}function fe(e){const{mode:t="light",contrastThreshold:r=3,tonalOffset:o=.2}=e,i=a(e,le),s=e.primary||function(e="light"){return"dark"===e?{main:ae[200],light:ae[50],dark:ae[400]}:{main:ae[700],light:ae[400],dark:ae[800]}}(t),l=e.secondary||function(e="light"){return"dark"===e?{main:ne[200],light:ne[50],dark:ne[400]}:{main:ne[500],light:ne[300],dark:ne[700]}}(t),u=e.error||function(e="light"){return"dark"===e?{main:oe[500],light:oe[300],dark:oe[700]}:{main:oe[700],light:oe[400],dark:oe[800]}}(t),d=e.info||function(e="light"){return"dark"===e?{main:se[400],light:se[300],dark:se[700]}:{main:se[700],light:se[500],dark:se[900]}}(t),p=e.success||function(e="light"){return"dark"===e?{main:ce[400],light:ce[300],dark:ce[700]}:{main:ce[800],light:ce[500],dark:ce[900]}}(t),h=e.warning||function(e="light"){return"dark"===e?{main:ie[400],light:ie[300],dark:ie[700]}:{main:"#ed6c02",light:ie[500],dark:ie[900]}}(t);function m(e){const t=function(e,t){const r=J(e),n=J(t);return(Math.max(r,n)+.05)/(Math.min(r,n)+.05)}(e,de.text.primary)>=r?de.text.primary:ue.text.primary;return t}const g=({color:e,name:t,mainShade:r=500,lightShade:i=300,darkShade:a=700})=>{if(!(e=(0,n.Z)({},e)).main&&e[r]&&(e.main=e[r]),!e.hasOwnProperty("main"))throw new Error(c(11,t?` (${t})`:"",r));if("string"!==typeof e.main)throw new Error(c(12,t?` (${t})`:"",JSON.stringify(e.main)));return pe(e,"light",i,o),pe(e,"dark",a,o),e.contrastText||(e.contrastText=m(e.main)),e},b={dark:de,light:ue};return f((0,n.Z)({common:(0,n.Z)({},te),mode:t,primary:g({color:s,name:"primary"}),secondary:g({color:l,name:"secondary",mainShade:"A400",lightShade:"A200",darkShade:"A700"}),error:g({color:u,name:"error"}),warning:g({color:h,name:"warning"}),info:g({color:d,name:"info"}),success:g({color:p,name:"success"}),grey:re,contrastThreshold:r,getContrastText:m,augmentColor:g,tonalOffset:o},b[t]),i)}const he=["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","fontWeightBold","htmlFontSize","allVariants","pxToRem"];const me={textTransform:"uppercase"},ge='"Roboto", "Helvetica", "Arial", sans-serif';function be(e,t){const r="function"===typeof t?t(e):t,{fontFamily:o=ge,fontSize:i=14,fontWeightLight:s=300,fontWeightRegular:c=400,fontWeightMedium:l=500,fontWeightBold:u=700,htmlFontSize:d=16,allVariants:p,pxToRem:h}=r,m=a(r,he);const g=i/14,b=h||(e=>e/d*g+"rem"),y=(e,t,r,i,a)=>{return(0,n.Z)({fontFamily:o,fontWeight:e,fontSize:b(t),lineHeight:r},o===ge?{letterSpacing:(s=i/t,Math.round(1e5*s)/1e5)+"em"}:{},a,p);var s},v={h1:y(s,96,1.167,-1.5),h2:y(s,60,1.2,-.5),h3:y(c,48,1.167,0),h4:y(c,34,1.235,.25),h5:y(c,24,1.334,0),h6:y(l,20,1.6,.15),subtitle1:y(c,16,1.75,.15),subtitle2:y(l,14,1.57,.1),body1:y(c,16,1.5,.15),body2:y(c,14,1.43,.15),button:y(l,14,1.75,.4,me),caption:y(c,12,1.66,.4),overline:y(c,12,2.66,1,me)};return f((0,n.Z)({htmlFontSize:d,pxToRem:b,fontFamily:o,fontSize:i,fontWeightLight:s,fontWeightRegular:c,fontWeightMedium:l,fontWeightBold:u},v),m,{clone:!1})}function ye(...e){return[`${e[0]}px ${e[1]}px ${e[2]}px ${e[3]}px rgba(0,0,0,0.2)`,`${e[4]}px ${e[5]}px ${e[6]}px ${e[7]}px rgba(0,0,0,0.14)`,`${e[8]}px ${e[9]}px ${e[10]}px ${e[11]}px rgba(0,0,0,0.12)`].join(",")}var ve=["none",ye(0,2,1,-1,0,1,1,0,0,1,3,0),ye(0,3,1,-2,0,2,2,0,0,1,5,0),ye(0,3,3,-2,0,3,4,0,0,1,8,0),ye(0,2,4,-1,0,4,5,0,0,1,10,0),ye(0,3,5,-1,0,5,8,0,0,1,14,0),ye(0,3,5,-1,0,6,10,0,0,1,18,0),ye(0,4,5,-2,0,7,10,1,0,2,16,1),ye(0,5,5,-3,0,8,10,1,0,3,14,2),ye(0,5,6,-3,0,9,12,1,0,3,16,2),ye(0,6,6,-3,0,10,14,1,0,4,18,3),ye(0,6,7,-4,0,11,15,1,0,4,20,3),ye(0,7,8,-4,0,12,17,2,0,5,22,4),ye(0,7,8,-4,0,13,19,2,0,5,24,4),ye(0,7,9,-4,0,14,21,2,0,5,26,4),ye(0,8,9,-5,0,15,22,2,0,6,28,5),ye(0,8,10,-5,0,16,24,2,0,6,30,5),ye(0,8,11,-5,0,17,26,2,0,6,32,5),ye(0,9,11,-5,0,18,28,2,0,7,34,6),ye(0,9,12,-6,0,19,29,2,0,7,36,6),ye(0,10,13,-6,0,20,31,3,0,8,38,7),ye(0,10,13,-6,0,21,33,3,0,8,40,7),ye(0,10,14,-6,0,22,35,3,0,8,42,7),ye(0,11,14,-7,0,23,36,3,0,9,44,8),ye(0,11,15,-7,0,24,38,3,0,9,46,8)];const xe=["duration","easing","delay"],ke={easeInOut:"cubic-bezier(0.4, 0, 0.2, 1)",easeOut:"cubic-bezier(0.0, 0, 0.2, 1)",easeIn:"cubic-bezier(0.4, 0, 1, 1)",sharp:"cubic-bezier(0.4, 0, 0.6, 1)"},we={shortest:150,shorter:200,short:250,standard:300,complex:375,enteringScreen:225,leavingScreen:195};function $e(e){return`${Math.round(e)}ms`}function Se(e){if(!e)return 0;const t=e/36;return Math.round(10*(4+15*t**.25+t/5))}function Ae(e){const t=(0,n.Z)({},ke,e.easing),r=(0,n.Z)({},we,e.duration);return(0,n.Z)({getAutoHeightDuration:Se,create:(e=["all"],n={})=>{const{duration:o=r.standard,easing:i=t.easeInOut,delay:s=0}=n;a(n,xe);return(Array.isArray(e)?e:[e]).map((e=>`${e} ${"string"===typeof o?o:$e(o)} ${i} ${"string"===typeof s?s:$e(s)}`)).join(",")}},e,{easing:t,duration:r})}var Ce={mobileStepper:1e3,fab:1050,speedDial:1050,appBar:1100,drawer:1200,modal:1300,snackbar:1400,tooltip:1500};const Pe=["breakpoints","mixins","spacing","palette","transitions","typography","shape"];function Oe(e={},...t){const{mixins:r={},palette:o={},transitions:i={},typography:s={}}=e,l=a(e,Pe);if(e.vars)throw new Error(c(18));const u=fe(o),d=L(e);let p=f(d,{mixins:D(d.breakpoints,r),palette:u,shadows:ve.slice(),typography:be(u,s),transitions:Ae(i),zIndex:(0,n.Z)({},Ce)});return p=f(p,l),p=t.reduce(((e,t)=>f(e,t)),p),p}var ze=Oe();function Te({props:e,name:t}){return function({props:e,name:t,defaultTheme:r}){return d({theme:U(r),name:t,props:e})}({props:e,name:t,defaultTheme:ze})}var Re=function(e){var t=Object.create(null);return function(r){return void 0===t[r]&&(t[r]=e(r)),t[r]}},_e=/^((children|dangerouslySetInnerHTML|key|ref|autoFocus|defaultValue|defaultChecked|innerHTML|suppressContentEditableWarning|suppressHydrationWarning|valueLink|abbr|accept|acceptCharset|accessKey|action|allow|allowUserMedia|allowPaymentRequest|allowFullScreen|allowTransparency|alt|async|autoComplete|autoPlay|capture|cellPadding|cellSpacing|challenge|charSet|checked|cite|classID|className|cols|colSpan|content|contentEditable|contextMenu|controls|controlsList|coords|crossOrigin|data|dateTime|decoding|default|defer|dir|disabled|disablePictureInPicture|download|draggable|encType|enterKeyHint|form|formAction|formEncType|formMethod|formNoValidate|formTarget|frameBorder|headers|height|hidden|high|href|hrefLang|htmlFor|httpEquiv|id|inputMode|integrity|is|keyParams|keyType|kind|label|lang|list|loading|loop|low|marginHeight|marginWidth|max|maxLength|media|mediaGroup|method|min|minLength|multiple|muted|name|nonce|noValidate|open|optimum|pattern|placeholder|playsInline|poster|preload|profile|radioGroup|readOnly|referrerPolicy|rel|required|reversed|role|rows|rowSpan|sandbox|scope|scoped|scrolling|seamless|selected|shape|size|sizes|slot|span|spellCheck|src|srcDoc|srcLang|srcSet|start|step|style|summary|tabIndex|target|title|translate|type|useMap|value|width|wmode|wrap|about|datatype|inlist|prefix|property|resource|typeof|vocab|autoCapitalize|autoCorrect|autoSave|color|incremental|fallback|inert|itemProp|itemScope|itemType|itemID|itemRef|on|option|results|security|unselectable|accentHeight|accumulate|additive|alignmentBaseline|allowReorder|alphabetic|amplitude|arabicForm|ascent|attributeName|attributeType|autoReverse|azimuth|baseFrequency|baselineShift|baseProfile|bbox|begin|bias|by|calcMode|capHeight|clip|clipPathUnits|clipPath|clipRule|colorInterpolation|colorInterpolationFilters|colorProfile|colorRendering|contentScriptType|contentStyleType|cursor|cx|cy|d|decelerate|descent|diffuseConstant|direction|display|divisor|dominantBaseline|dur|dx|dy|edgeMode|elevation|enableBackground|end|exponent|externalResourcesRequired|fill|fillOpacity|fillRule|filter|filterRes|filterUnits|floodColor|floodOpacity|focusable|fontFamily|fontSize|fontSizeAdjust|fontStretch|fontStyle|fontVariant|fontWeight|format|from|fr|fx|fy|g1|g2|glyphName|glyphOrientationHorizontal|glyphOrientationVertical|glyphRef|gradientTransform|gradientUnits|hanging|horizAdvX|horizOriginX|ideographic|imageRendering|in|in2|intercept|k|k1|k2|k3|k4|kernelMatrix|kernelUnitLength|kerning|keyPoints|keySplines|keyTimes|lengthAdjust|letterSpacing|lightingColor|limitingConeAngle|local|markerEnd|markerMid|markerStart|markerHeight|markerUnits|markerWidth|mask|maskContentUnits|maskUnits|mathematical|mode|numOctaves|offset|opacity|operator|order|orient|orientation|origin|overflow|overlinePosition|overlineThickness|panose1|paintOrder|pathLength|patternContentUnits|patternTransform|patternUnits|pointerEvents|points|pointsAtX|pointsAtY|pointsAtZ|preserveAlpha|preserveAspectRatio|primitiveUnits|r|radius|refX|refY|renderingIntent|repeatCount|repeatDur|requiredExtensions|requiredFeatures|restart|result|rotate|rx|ry|scale|seed|shapeRendering|slope|spacing|specularConstant|specularExponent|speed|spreadMethod|startOffset|stdDeviation|stemh|stemv|stitchTiles|stopColor|stopOpacity|strikethroughPosition|strikethroughThickness|string|stroke|strokeDasharray|strokeDashoffset|strokeLinecap|strokeLinejoin|strokeMiterlimit|strokeOpacity|strokeWidth|surfaceScale|systemLanguage|tableValues|targetX|targetY|textAnchor|textDecoration|textRendering|textLength|to|transform|u1|u2|underlinePosition|underlineThickness|unicode|unicodeBidi|unicodeRange|unitsPerEm|vAlphabetic|vHanging|vIdeographic|vMathematical|values|vectorEffect|version|vertAdvY|vertOriginX|vertOriginY|viewBox|viewTarget|visibility|widths|wordSpacing|writingMode|x|xHeight|x1|x2|xChannelSelector|xlinkActuate|xlinkArcrole|xlinkHref|xlinkRole|xlinkShow|xlinkTitle|xlinkType|xmlBase|xmlns|xmlnsXlink|xmlLang|xmlSpace|y|y1|y2|yChannelSelector|z|zoomAndPan|for|class|autofocus)|(([Dd][Aa][Tt][Aa]|[Aa][Rr][Ii][Aa]|x)-.*))$/,je=Re((function(e){return _e.test(e)||111===e.charCodeAt(0)&&110===e.charCodeAt(1)&&e.charCodeAt(2)<91}));var Ee=function(){function e(e){var t=this;this._insertTag=function(e){var r;r=0===t.tags.length?t.insertionPoint?t.insertionPoint.nextSibling:t.prepend?t.container.firstChild:t.before:t.tags[t.tags.length-1].nextSibling,t.container.insertBefore(e,r),t.tags.push(e)},this.isSpeedy=void 0===e.speedy||e.speedy,this.tags=[],this.ctr=0,this.nonce=e.nonce,this.key=e.key,this.container=e.container,this.prepend=e.prepend,this.insertionPoint=e.insertionPoint,this.before=null}var t=e.prototype;return t.hydrate=function(e){e.forEach(this._insertTag)},t.insert=function(e){this.ctr%(this.isSpeedy?65e3:1)===0&&this._insertTag(function(e){var t=document.createElement("style");return t.setAttribute("data-emotion",e.key),void 0!==e.nonce&&t.setAttribute("nonce",e.nonce),t.appendChild(document.createTextNode("")),t.setAttribute("data-s",""),t}(this));var t=this.tags[this.tags.length-1];if(this.isSpeedy){var r=function(e){if(e.sheet)return e.sheet;for(var t=0;t0?Be(Ye,--qe):0,Ue--,10===Xe&&(Ue=1,Ve--),Xe}function tt(){return Xe=qe2||it(Xe)>3?"":" "}function ut(e,t){for(;--t&&tt()&&!(Xe<48||Xe>102||Xe>57&&Xe<65||Xe>70&&Xe<97););return ot(e,nt()+(t<6&&32==rt()&&32==tt()))}function dt(e){for(;tt();)switch(Xe){case e:return qe;case 34:case 39:34!==e&&39!==e&&dt(Xe);break;case 40:41===e&&dt(e);break;case 92:tt()}return qe}function pt(e,t){for(;tt()&&e+Xe!==57&&(e+Xe!==84||47!==rt()););return"/*"+ot(t,qe-1)+"*"+Me(47===e?e:tt())}function ft(e){for(;!it(rt());)tt();return ot(e,qe)}var ht="-ms-",mt="-moz-",gt="-webkit-",bt="comm",yt="rule",vt="decl",xt="@keyframes";function kt(e,t){for(var r="",n=Ge(e),o=0;o0&&Le($)-d&&Ke(f>32?Pt($+";",n,r,d-1):Pt(Ze($," ","")+";",n,r,d-2),c);break;case 59:$+=";";default:if(Ke(w=At($,t,r,l,u,o,s,v,x=[],k=[],d),i),123===y)if(0===u)St($,t,w,w,x,i,d,s,k);else switch(99===p&&110===Be($,3)?100:p){case 100:case 109:case 115:St(e,w,w,n&&Ke(At(e,w,w,0,0,o,s,v,o,x=[],d),k),o,k,d,s,n?x:k);break;default:St($,w,w,w,[""],k,0,s,k)}}l=u=f=0,m=b=1,v=$="",d=a;break;case 58:d=1+Le($),f=h;default:if(m<1)if(123==y)--m;else if(125==y&&0==m++&&125==et())continue;switch($+=Me(y),y*m){case 38:b=u>0?1:($+="\f",-1);break;case 44:s[l++]=(Le($)-1)*b,b=1;break;case 64:45===rt()&&($+=ct(tt())),p=rt(),u=d=Le(v=$+=ft(nt())),y++;break;case 45:45===h&&2==Le($)&&(m=0)}}return i}function At(e,t,r,n,o,i,a,s,c,l,u){for(var d=o-1,p=0===o?i:[""],f=Ge(p),h=0,m=0,g=0;h0?p[b]+" "+y:Ze(y,/&\f/g,p[b])))&&(c[g++]=v);return Je(e,t,r,0===o?yt:s,c,l,u)}function Ct(e,t,r){return Je(e,t,r,bt,Me(Xe),He(e,2,-2),0)}function Pt(e,t,r,n){return Je(e,t,r,vt,He(e,0,n),He(e,n+1,-1),n)}var Ot=function(e,t,r){for(var n=0,o=0;n=o,o=rt(),38===n&&12===o&&(t[r]=1),!it(o);)tt();return ot(e,qe)},zt=function(e,t){return st(function(e,t){var r=-1,n=44;do{switch(it(n)){case 0:38===n&&12===rt()&&(t[r]=1),e[r]+=Ot(qe-1,t,r);break;case 2:e[r]+=ct(n);break;case 4:if(44===n){e[++r]=58===rt()?"&\f":"",t[r]=e[r].length;break}default:e[r]+=Me(n)}}while(n=tt());return e}(at(e),t))},Tt=new WeakMap,Rt=function(e){if("rule"===e.type&&e.parent&&!(e.length<1)){for(var t=e.value,r=e.parent,n=e.column===r.column&&e.line===r.line;"rule"!==r.type;)if(!(r=r.parent))return;if((1!==e.props.length||58===t.charCodeAt(0)||Tt.get(r))&&!n){Tt.set(e,!0);for(var o=[],i=zt(t,o),a=r.props,s=0,c=0;s6)switch(Be(e,t+1)){case 109:if(45!==Be(e,t+4))break;case 102:return Ze(e,/(.+:)(.+)-([^]+)/,"$1-webkit-$2-$3$1-moz-"+(108==Be(e,t+3)?"$3":"$2-$3"))+e;case 115:return~Fe(e,"stretch")?jt(Ze(e,"stretch","fill-available"),t)+e:e}break;case 4949:if(115!==Be(e,t+1))break;case 6444:switch(Be(e,Le(e)-3-(~Fe(e,"!important")&&10))){case 107:return Ze(e,":",":-webkit-")+e;case 101:return Ze(e,/(.+:)([^;!]+)(;|!.+)?/,"$1-webkit-"+(45===Be(e,14)?"inline-":"")+"box$3$1"+"-webkit-$2$3$1"+"-ms-$2box$3")+e}break;case 5936:switch(Be(e,t+11)){case 114:return gt+e+ht+Ze(e,/[svh]\w+-[tblr]{2}/,"tb")+e;case 108:return gt+e+ht+Ze(e,/[svh]\w+-[tblr]{2}/,"tb-rl")+e;case 45:return gt+e+ht+Ze(e,/[svh]\w+-[tblr]{2}/,"lr")+e}return gt+e+ht+e+e}return e}var Et=[function(e,t,r,n){if(e.length>-1&&!e.return)switch(e.type){case vt:e.return=jt(e.value,e.length);break;case xt:return kt([Qe(e,{value:Ze(e.value,"@","@-webkit-")})],n);case yt:if(e.length)return function(e,t){return e.map(t).join("")}(e.props,(function(t){switch(function(e,t){return(e=t.exec(e))?e[0]:e}(t,/(::plac\w+|:read-\w+)/)){case":read-only":case":read-write":return kt([Qe(e,{props:[Ze(t,/:(read-\w+)/,":-moz-$1")]})],n);case"::placeholder":return kt([Qe(e,{props:[Ze(t,/:(plac\w+)/,":-webkit-input-$1")]}),Qe(e,{props:[Ze(t,/:(plac\w+)/,":-moz-$1")]}),Qe(e,{props:[Ze(t,/:(plac\w+)/,"-ms-input-$1")]})],n)}return""}))}}],It=function(e){var t=e.key;if("css"===t){var r=document.querySelectorAll("style[data-emotion]:not([data-s])");Array.prototype.forEach.call(r,(function(e){-1!==e.getAttribute("data-emotion").indexOf(" ")&&(document.head.appendChild(e),e.setAttribute("data-s",""))}))}var n=e.stylisPlugins||Et;var o,i,a={},s=[];o=e.container||document.head,Array.prototype.forEach.call(document.querySelectorAll('style[data-emotion^="'+t+' "]'),(function(e){for(var t=e.getAttribute("data-emotion").split(" "),r=1;r=4;++n,o-=4)t=1540483477*(65535&(t=255&e.charCodeAt(n)|(255&e.charCodeAt(++n))<<8|(255&e.charCodeAt(++n))<<16|(255&e.charCodeAt(++n))<<24))+(59797*(t>>>16)<<16),r=1540483477*(65535&(t^=t>>>24))+(59797*(t>>>16)<<16)^1540483477*(65535&r)+(59797*(r>>>16)<<16);switch(o){case 3:r^=(255&e.charCodeAt(n+2))<<16;case 2:r^=(255&e.charCodeAt(n+1))<<8;case 1:r=1540483477*(65535&(r^=255&e.charCodeAt(n)))+(59797*(r>>>16)<<16)}return(((r=1540483477*(65535&(r^=r>>>13))+(59797*(r>>>16)<<16))^r>>>15)>>>0).toString(36)},Wt={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1},Nt=/[A-Z]|^ms/g,Zt=/_EMO_([^_]+?)_([^]*?)_EMO_/g,Ft=function(e){return 45===e.charCodeAt(1)},Bt=function(e){return null!=e&&"boolean"!==typeof e},Ht=Re((function(e){return Ft(e)?e:e.replace(Nt,"-$&").toLowerCase()})),Lt=function(e,t){switch(e){case"animation":case"animationName":if("string"===typeof t)return t.replace(Zt,(function(e,t,r){return Kt={name:t,styles:r,next:Kt},t}))}return 1===Wt[e]||Ft(e)||"number"!==typeof t||0===t?t:t+"px"};function Gt(e,t,r){if(null==r)return"";if(void 0!==r.__emotion_styles)return r;switch(typeof r){case"boolean":return"";case"object":if(1===r.anim)return Kt={name:r.name,styles:r.styles,next:Kt},r.name;if(void 0!==r.styles){var n=r.next;if(void 0!==n)for(;void 0!==n;)Kt={name:n.name,styles:n.styles,next:Kt},n=n.next;return r.styles+";"}return function(e,t,r){var n="";if(Array.isArray(r))for(var o=0;o96?tr:rr},or=function(e,t,r){var n;if(t){var o=t.shouldForwardProp;n=e.__emotion_forwardProp&&o?function(t){return e.__emotion_forwardProp(t)&&o(t)}:o}return"function"!==typeof n&&r&&(n=e.__emotion_forwardProp),n},ir=function(e){var t=e.cache,r=e.serialized,n=e.isStringTag;er(t,r,n);qt((function(){return function(e,t,r){er(e,t,r);var n=e.key+"-"+t.name;if(void 0===e.inserted[t.name]){var o=t;do{e.insert(t===o?"."+n:"",o,e.sheet,!0),o=o.next}while(void 0!==o)}}(t,r,n)}));return null},ar=function e(t,r){var i,a,s=t.__emotion_real===t,c=s&&t.__emotion_base||t;void 0!==r&&(i=r.label,a=r.target);var l=or(t,r,s),u=l||nr(c),d=!u("as");return function(){var p=arguments,f=s&&void 0!==t.__emotion_styles?t.__emotion_styles.slice(0):[];if(void 0!==i&&f.push("label:"+i+";"),null==p[0]||void 0===p[0].raw)f.push.apply(f,p);else{0,f.push(p[0][0]);for(var h=p.length,m=1;m{n+="color"===t?ur(n)?e[t]:l(e[t]):`${ur(n)?t:l(t)}${l(e[t].toString())}`})),n}var pr=function(...e){const t=e.reduce(((e,t)=>(t.filterProps.forEach((r=>{e[r]=t})),e)),{}),r=e=>Object.keys(e).reduce(((r,n)=>t[n]?A(r,t[n](e)):r),{});return r.propTypes={},r.filterProps=e.reduce(((e,t)=>e.concat(t.filterProps)),[]),r};function fr(e){return"number"!==typeof e?e:`${e}px solid`}const hr=S({prop:"border",themeKey:"borders",transform:fr}),mr=S({prop:"borderTop",themeKey:"borders",transform:fr}),gr=S({prop:"borderRight",themeKey:"borders",transform:fr}),br=S({prop:"borderBottom",themeKey:"borders",transform:fr}),yr=S({prop:"borderLeft",themeKey:"borders",transform:fr}),vr=S({prop:"borderColor",themeKey:"palette"}),xr=S({prop:"borderTopColor",themeKey:"palette"}),kr=S({prop:"borderRightColor",themeKey:"palette"}),wr=S({prop:"borderBottomColor",themeKey:"palette"}),$r=S({prop:"borderLeftColor",themeKey:"palette"}),Sr=e=>{if(void 0!==e.borderRadius&&null!==e.borderRadius){const t=j(e.theme,"shape.borderRadius",4),r=e=>({borderRadius:I(t,e)});return v(e,e.borderRadius,r)}return null};Sr.propTypes={},Sr.filterProps=["borderRadius"];var Ar=pr(hr,mr,gr,br,yr,vr,xr,kr,wr,$r,Sr);var Cr=pr(S({prop:"displayPrint",cssProperty:!1,transform:e=>({"@media print":{display:e}})}),S({prop:"display"}),S({prop:"overflow"}),S({prop:"textOverflow"}),S({prop:"visibility"}),S({prop:"whiteSpace"}));var Pr=pr(S({prop:"flexBasis"}),S({prop:"flexDirection"}),S({prop:"flexWrap"}),S({prop:"justifyContent"}),S({prop:"alignItems"}),S({prop:"alignContent"}),S({prop:"order"}),S({prop:"flex"}),S({prop:"flexGrow"}),S({prop:"flexShrink"}),S({prop:"alignSelf"}),S({prop:"justifyItems"}),S({prop:"justifySelf"}));const Or=e=>{if(void 0!==e.gap&&null!==e.gap){const t=j(e.theme,"spacing",8),r=e=>({gap:I(t,e)});return v(e,e.gap,r)}return null};Or.propTypes={},Or.filterProps=["gap"];const zr=e=>{if(void 0!==e.columnGap&&null!==e.columnGap){const t=j(e.theme,"spacing",8),r=e=>({columnGap:I(t,e)});return v(e,e.columnGap,r)}return null};zr.propTypes={},zr.filterProps=["columnGap"];const Tr=e=>{if(void 0!==e.rowGap&&null!==e.rowGap){const t=j(e.theme,"spacing",8),r=e=>({rowGap:I(t,e)});return v(e,e.rowGap,r)}return null};Tr.propTypes={},Tr.filterProps=["rowGap"];var Rr=pr(Or,zr,Tr,S({prop:"gridColumn"}),S({prop:"gridRow"}),S({prop:"gridAutoFlow"}),S({prop:"gridAutoColumns"}),S({prop:"gridAutoRows"}),S({prop:"gridTemplateColumns"}),S({prop:"gridTemplateRows"}),S({prop:"gridTemplateAreas"}),S({prop:"gridArea"}));var _r=pr(S({prop:"position"}),S({prop:"zIndex",themeKey:"zIndex"}),S({prop:"top"}),S({prop:"right"}),S({prop:"bottom"}),S({prop:"left"}));function jr(e,t){return"grey"===t?t:e}var Er=pr(S({prop:"color",themeKey:"palette",transform:jr}),S({prop:"bgcolor",cssProperty:"backgroundColor",themeKey:"palette",transform:jr}),S({prop:"backgroundColor",themeKey:"palette",transform:jr}));var Ir=S({prop:"boxShadow",themeKey:"shadows"});function Mr(e){return e<=1&&0!==e?100*e+"%":e}const Wr=S({prop:"width",transform:Mr}),Nr=e=>{if(void 0!==e.maxWidth&&null!==e.maxWidth){const t=t=>{var r,n,o;return{maxWidth:(null==(r=e.theme)||null==(n=r.breakpoints)||null==(o=n.values)?void 0:o[t])||b[t]||Mr(t)}};return v(e,e.maxWidth,t)}return null};Nr.filterProps=["maxWidth"];const Zr=S({prop:"minWidth",transform:Mr}),Fr=S({prop:"height",transform:Mr}),Br=S({prop:"maxHeight",transform:Mr}),Hr=S({prop:"minHeight",transform:Mr});S({prop:"size",cssProperty:"width",transform:Mr}),S({prop:"size",cssProperty:"height",transform:Mr});var Lr=pr(Wr,Nr,Zr,Fr,Br,Hr,S({prop:"boxSizing"}));const Gr=S({prop:"fontFamily",themeKey:"typography"}),Kr=S({prop:"fontSize",themeKey:"typography"}),Vr=S({prop:"fontStyle",themeKey:"typography"}),Ur=S({prop:"fontWeight",themeKey:"typography"}),Dr=S({prop:"letterSpacing"}),qr=S({prop:"textTransform"}),Xr=S({prop:"lineHeight"}),Yr=S({prop:"textAlign"});var Jr=pr(S({prop:"typography",cssProperty:!1,themeKey:"typography"}),Gr,Kr,Vr,Ur,Dr,Xr,Yr,qr);const Qr={borders:Ar.filterProps,display:Cr.filterProps,flexbox:Pr.filterProps,grid:Rr.filterProps,positions:_r.filterProps,palette:Er.filterProps,shadows:Ir.filterProps,sizing:Lr.filterProps,spacing:B.filterProps,typography:Jr.filterProps},en={borders:Ar,display:Cr,flexbox:Pr,grid:Rr,positions:_r,palette:Er,shadows:Ir,sizing:Lr,spacing:B,typography:Jr};Object.keys(Qr).reduce(((e,t)=>(Qr[t].forEach((r=>{e[r]=en[t]})),e)),{});const tn=function(e=en){const t=Object.keys(e).reduce(((t,r)=>(e[r].filterProps.forEach((n=>{t[n]=e[r]})),t)),{});function r(e,r,n){const o={[e]:r,theme:n},i=t[e];return i?i(o):{[e]:r}}return function e(n){const{sx:o,theme:i={}}=n||{};if(!o)return null;function a(n){let o=n;if("function"===typeof n)o=n(i);else if("object"!==typeof n)return n;if(!o)return null;const a=x(i.breakpoints),s=Object.keys(a);let c=a;return Object.keys(o).forEach((n=>{const a=(s=o[n],l=i,"function"===typeof s?s(l):s);var s,l;if(null!==a&&void 0!==a)if("object"===typeof a)if(t[n])c=A(c,r(n,a,i));else{const t=v({theme:i},a,(e=>({[n]:e})));!function(...e){const t=e.reduce(((e,t)=>e.concat(Object.keys(t))),[]),r=new Set(t);return e.every((e=>r.size===Object.keys(e).length))}(t,a)?c=A(c,t):c[n]=e({sx:a,theme:i})}else c=A(c,r(n,a,i))})),k(s,c)}return Array.isArray(o)?o.map(a):a(o)}}();tn.filterProps=["sx"];var rn=tn;const nn=["name","slot","skipVariantsResolver","skipSx","overridesResolver"],on=["theme"],an=["theme"];function sn(e){return 0===Object.keys(e).length}function cn(e){return"ownerState"!==e&&"theme"!==e&&"sx"!==e&&"as"!==e}const ln=L();const un=function(e={}){const{defaultTheme:t=ln,rootShouldForwardProp:r=cn,slotShouldForwardProp:o=cn,styleFunctionSx:i=rn}=e,s=e=>{const r=sn(e.theme)?t:e.theme;return i((0,n.Z)({},e,{theme:r}))};return s.__mui_systemSx=!0,(e,i={})=>{((e,t)=>{Array.isArray(e.__emotion_styles)&&(e.__emotion_styles=t(e.__emotion_styles))})(e,(e=>e.filter((e=>!(null!=e&&e.__mui_systemSx)))));const{name:c,slot:l,skipVariantsResolver:u,skipSx:d,overridesResolver:p}=i,f=a(i,nn),h=void 0!==u?u:l&&"Root"!==l||!1,m=d||!1;let g=cn;"Root"===l?g=r:l?g=o:function(e){return"string"===typeof e&&e.charCodeAt(0)>96}(e)&&(g=void 0);const b=function(e,t){return cr(e,t)}(e,(0,n.Z)({shouldForwardProp:g,label:undefined},f)),y=(e,...r)=>{const o=r?r.map((e=>"function"===typeof e&&e.__emotion_real!==e?r=>{let{theme:o}=r,i=a(r,on);return e((0,n.Z)({theme:sn(o)?t:o},i))}:e)):[];let i=e;c&&p&&o.push((e=>{const r=sn(e.theme)?t:e.theme,o=((e,t)=>t.components&&t.components[e]&&t.components[e].styleOverrides?t.components[e].styleOverrides:null)(c,r);if(o){const t={};return Object.entries(o).forEach((([o,i])=>{t[o]="function"===typeof i?i((0,n.Z)({},e,{theme:r})):i})),p(e,t)}return null})),c&&!h&&o.push((e=>{const r=sn(e.theme)?t:e.theme;return((e,t,r,n)=>{var o,i;const{ownerState:a={}}=e,s=[],c=null==r||null==(o=r.components)||null==(i=o[n])?void 0:i.variants;return c&&c.forEach((r=>{let n=!0;Object.keys(r.props).forEach((t=>{a[t]!==r.props[t]&&e[t]!==r.props[t]&&(n=!1)})),n&&s.push(t[dr(r.props)])})),s})(e,((e,t)=>{let r=[];t&&t.components&&t.components[e]&&t.components[e].variants&&(r=t.components[e].variants);const n={};return r.forEach((e=>{const t=dr(e.props);n[t]=e.style})),n})(c,r),r,c)})),m||o.push(s);const l=o.length-r.length;if(Array.isArray(e)&&l>0){const t=new Array(l).fill("");i=[...e,...t],i.raw=[...e.raw,...t]}else"function"===typeof e&&e.__emotion_real!==e&&(i=r=>{let{theme:o}=r,i=a(r,an);return e((0,n.Z)({theme:sn(o)?t:o},i))});return b(i,...o)};return b.withConfig&&(y.withConfig=b.withConfig),y}}({defaultTheme:ze,rootShouldForwardProp:e=>cn(e)&&"classes"!==e});var dn=un;const pn=e=>e;var fn=(()=>{let e=pn;return{configure(t){e=t},generate:t=>e(t),reset(){e=pn}}})();const hn={active:"active",checked:"checked",completed:"completed",disabled:"disabled",error:"error",expanded:"expanded",focused:"focused",focusVisible:"focusVisible",required:"required",selected:"selected"};function mn(e,t,r="Mui"){const n=hn[t];return n?`${r}-${n}`:`${fn.generate(e)}-${t}`}function gn(e){return mn("MuiSvgIcon",e)}!function(e,t,r="Mui"){const n={};t.forEach((t=>{n[t]=mn(e,t,r)}))}("MuiSvgIcon",["root","colorPrimary","colorSecondary","colorAction","colorError","colorDisabled","fontSizeInherit","fontSizeSmall","fontSizeMedium","fontSizeLarge"]);var bn=r(5893);const yn=["children","className","color","component","fontSize","htmlColor","inheritViewBox","titleAccess","viewBox"],vn=e=>{const{color:t,fontSize:r,classes:n}=e;return function(e,t,r){const n={};return Object.keys(e).forEach((o=>{n[o]=e[o].reduce(((e,n)=>(n&&(e.push(t(n)),r&&r[n]&&e.push(r[n])),e)),[]).join(" ")})),n}({root:["root","inherit"!==t&&`color${u(t)}`,`fontSize${u(r)}`]},gn,n)},xn=dn("svg",{name:"MuiSvgIcon",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:r}=e;return[t.root,"inherit"!==r.color&&t[`color${u(r.color)}`],t[`fontSize${u(r.fontSize)}`]]}})((({theme:e,ownerState:t})=>{var r,n,o,i,a,s,c,l,u,d,p,f,h,m,g,b,y;return{userSelect:"none",width:"1em",height:"1em",display:"inline-block",fill:"currentColor",flexShrink:0,transition:null==(r=e.transitions)||null==(n=r.create)?void 0:n.call(r,"fill",{duration:null==(o=e.transitions)||null==(i=o.duration)?void 0:i.shorter}),fontSize:{inherit:"inherit",small:(null==(a=e.typography)||null==(s=a.pxToRem)?void 0:s.call(a,20))||"1.25rem",medium:(null==(c=e.typography)||null==(l=c.pxToRem)?void 0:l.call(c,24))||"1.5rem",large:(null==(u=e.typography)||null==(d=u.pxToRem)?void 0:d.call(u,35))||"2.1875rem"}[t.fontSize],color:null!=(p=null==(f=(e.vars||e).palette)||null==(h=f[t.color])?void 0:h.main)?p:{action:null==(m=(e.vars||e).palette)||null==(g=m.action)?void 0:g.active,disabled:null==(b=(e.vars||e).palette)||null==(y=b.action)?void 0:y.disabled,inherit:void 0}[t.color]}})),kn=o.forwardRef((function(e,t){const r=Te({props:e,name:"MuiSvgIcon"}),{children:o,className:i,color:c="inherit",component:l="svg",fontSize:u="medium",htmlColor:d,inheritViewBox:p=!1,titleAccess:f,viewBox:h="0 0 24 24"}=r,m=a(r,yn),g=(0,n.Z)({},r,{color:c,component:l,fontSize:u,instanceFontSize:e.fontSize,inheritViewBox:p,viewBox:h}),b={};p||(b.viewBox=h);const y=vn(g);return(0,bn.jsxs)(xn,(0,n.Z)({as:l,className:(0,s.Z)(y.root,i),focusable:"false",color:d,"aria-hidden":!f||void 0,role:f?"img":void 0,ref:t},b,m,{ownerState:g,children:[o,f?(0,bn.jsx)("title",{children:f}):null]}))}));kn.muiName="SvgIcon";var wn=kn;function $n(e,t){function r(r,o){return(0,bn.jsx)(wn,(0,n.Z)({"data-testid":`${t}Icon`,ref:o},r,{children:e}))}return r.muiName=wn.muiName,o.memo(o.forwardRef(r))}},7370:function(e,t,r){r.d(t,{ZP:function(){return F}});var n=r(7294),o=r(8375),i=r(9641),a=r(4213),s=r(7354),c=r(9260),l=r(2903);var u=r(6212),d=r(9975);const p=(0,u.zo)("div",{d:"flex",w:"100%",h:"auto",flex:"1 1 auto",fd:"column",jc:"inherit",ai:"inherit",ac:"inherit",py:"$lg",px:"$sm",oy:"auto",position:"relative",ta:"left"}),f=(0,u.zo)("div",{$$cardColor:"$colors$backgroundContrast",$$cardTextColor:"$colors$text",m:0,p:0,br:"$lg",bg:"$$cardColor",color:"$$cardTextColor",position:"relative",display:"flex",overflow:"hidden",fd:"column",width:"100%",height:"auto",boxSizing:"border-box","@motion":{transition:"none"},".nextui-image":{width:"100%"},[`& ${o.q}`]:{zIndex:"$1",".nextui-drip-filler":{opacity:.25,fill:"$accents6"}},variants:{variant:{flat:{bg:"$accents0"},shadow:{dropShadow:"$lg"},bordered:{borderStyle:"solid",borderColor:"$border"}},borderWeight:{light:{bw:"$light"},normal:{bw:"$normal"},bold:{bw:"$bold"},extrabold:{bw:"$extrabold"},black:{bw:"$black"}},disableAnimation:{true:{transition:"none"},false:{transition:"$card"}},isPressable:{true:{cursor:"pointer",us:"none",WebkitTapHighlightColor:"transparent"}},isPressed:{true:{}},isHovered:{true:{dropShadow:"$lg"}}},compoundVariants:[{isPressed:!0,disableAnimation:!1,css:{transform:"scale(0.97)"}},{isHovered:!0,disableAnimation:!1,css:{transform:"translateY(-2px)"}},{isHovered:!0,variant:"shadow",css:{dropShadow:"$xl"}}]},d.UU,d.BM),h=(0,u.zo)("div",{w:"100%",display:"flex",flexShrink:0,zIndex:"$1",jc:"flex-start",ai:"center",overflow:"hidden",color:"inherit",p:"$sm"}),m=(0,u.zo)("div",{w:"100%",h:"auto",p:"$sm",d:"flex",ai:"center",overflow:"hidden",color:"inherit",bblr:"$lg",bbrr:"$lg",variants:{isBlurred:{true:{bf:"saturate(180%) blur(10px)",bg:"$$cardColor"}}}});var g=r(3569),b=r(5893);const y=n.forwardRef((({...e},t)=>{const{as:r,css:u,children:d,...p}=e,{cardRef:h,variant:m,isFocusVisible:g,isPressable:y,isPressed:v,disableAnimation:x,disableRipple:k,borderWeight:w,isHovered:$,getCardProps:S,dripBindings:A}=(e=>{const{ref:t,disableAnimation:r=!1,disableRipple:o=!1,variant:u="shadow",isHoverable:d=!1,borderWeight:p="light",isPressable:f=!1,onClick:h,onPress:m,autoFocus:g,allowTextSelectionOnPress:b=!0,...y}=e,v=(0,l.gy)(t),{onClick:x,...k}=(0,c.Z)(!1,v),w=e=>{r||o||!v.current||x(e)},{isPressed:$,pressProps:S}=(0,s.r7)({isDisabled:!f,onPress:e=>{"keyboard"!==e.pointerType&&"virtual"!==e.pointerType||(w(e),null==h||h(e)),null==m||m(e)},allowTextSelectionOnPress:b,...y}),{hoverProps:A,isHovered:C}=(0,s.XI)({isDisabled:!d,...y}),{isFocusVisible:P,focusProps:O}=(0,i.Fx)({autoFocus:g});S.onClick=e=>{f&&(w(e),null==h||h(e))};const z=(0,n.useCallback)(((e={})=>({...(0,a.dG)(f?{...S,...O}:{},d?A:{},y,e)})),[f,d,S,O,A,y]);return{cardRef:v,variant:u,borderWeight:p,isPressable:f,isHovered:C,isPressed:$,disableAnimation:r,disableRipple:o,dripBindings:k,onDripClickHandler:x,isFocusVisible:P,getCardProps:z}})({...p,ref:t});return(0,b.jsxs)(f,{ref:h,as:r,css:u,variant:m,role:y?"button":"section",borderWeight:w,disableAnimation:x,isPressable:y,isPressed:v,isHovered:$,tabIndex:y?0:-1,isFocusVisible:g,...S(),children:[y&&!x&&!k&&(0,b.jsx)(o.Z,{...A}),d]})}));g.Ts&&(y.displayName="NextUI.Card"),y.toString=()=>".nextui-card";var v=y,x=r(88);const k=(0,u.F4)({"0%":{backgroundPosition:"200% 0"},to:{backgroundPosition:"-200% 0"}}),w=(0,u.zo)("div",{opacity:0,margin:"0 auto",position:"relative",overflow:"hidden",maxWidth:"100%",transition:"transform 250ms ease 0ms, opacity 200ms ease-in 0ms","@motion":{transition:"none"},variants:{ready:{true:{opacity:1},false:{opacity:0}}}}),$=(0,u.zo)("img",{size:"100%",display:"block"}),S=(0,u.zo)("div",{position:"absolute",top:0,left:0,right:0,bottom:0,size:"100%",borderRadius:"inherit",backgroundImage:"linear-gradient(270deg, $colors$accents1, $colors$accents2, $colors$accents2, $colors$accents1)",backgroundSize:"400% 100%",animation:`${k} 5s ease-in-out infinite`,transition:"opacity 300ms ease-out"});var A=r(1309);const C=n.memo((({opacity:e,css:t,className:r,...n})=>(0,b.jsx)(S,{css:{opacity:e,...t},className:(0,A.Z)("nextui-image-skeleton",r),...n})));g.Ts&&(C.displayName="NextUI.ImageSkeleton"),C.toString=()=>".nextui-image-skeleton";var P=(0,x.Z)(C,{opacity:.5,className:""});const O=(e,t)=>{if(!e)return 0;const r=e.includes("px")?+e.split("px")[0]:e.includes("%")?+e.split("%")[0]*t*.01:e;return Number.isNaN(+r)?0:+r};var z=e=>{const[t,r]=(0,n.useState)({width:0,height:0}),o=()=>{const{width:t,height:n}=(e=>{if(!e||"undefined"==typeof window)return{width:0,height:0};const t=e.getBoundingClientRect(),{width:r,height:n}=window.getComputedStyle(e);return{width:O(`${r}`,t.width),height:O(`${n}`,t.height)}})(e.current);r({width:t,height:n})};return(0,n.useEffect)((()=>o()),[e.current]),[t,o]},T=e=>{const[t,r]=(0,n.useState)((()=>"function"==typeof e?e():e)),o=(0,n.useRef)(e);return(0,n.useEffect)((()=>{o.current=t}),[t]),[t,e=>{const t="function"==typeof e?e(o.current):e;o.current=t,r(t)},o]},R=r(6693);const _=n.forwardRef(((e,t)=>{const{src:r,width:o,height:i,showSkeleton:a=!0,className:s,maxDelay:c=3e3,autoResize:u=!1,objectFit:d="scale-down",containerCss:p,css:f,...h}=e,m=(0,l.gy)(t),[g,y]=(0,n.useState)(!0),[v,x]=(0,n.useState)(a),{w:k,h:S}=(0,n.useMemo)((()=>({w:o?"number"==typeof o?`${o}px`:o:"auto",h:i?"number"==typeof i?`${i}px`:i:"auto"})),[o,i]),[C,O,_]=T(S),[j,E]=z(m),I=a&&!!o&&!!i;(0,n.useEffect)((()=>{m.current&&m.current.complete&&(y(!1),x(!1))})),(0,n.useEffect)((()=>{const e=setTimeout((()=>{I&&x(!1),clearTimeout(e)}),c);return()=>clearTimeout(e)}),[g]),(0,n.useEffect)((()=>{if(!u)return;const e=0===j.width,t="auto"===_.current;!e&&o&&i&&(j.width{u&&E()}));const M=(0,n.useMemo)((()=>g?"loading":"ready"),[g]);return(0,b.jsxs)(w,{className:(0,A.Z)("nextui-image-container",`nextui-image--${M}`,s),"data-state":M,ready:!g||v,css:{width:k,height:C,...p},children:[v&&(0,b.jsx)(P,{opacity:1}),(0,b.jsx)($,{ref:m,className:"nextui-image",width:o,height:i,onLoad:()=>{y(!1)},src:r,"data-state":M,alt:e.alt||"",css:{objectFit:d,...f},...h})]})}));g.Ts&&(_.displayName="NextUI.Image"),_.toString=()=>".nextui-image";var j=n.memo(_),E=r(6772);const I=(0,u.zo)("div",{width:"100%",maxWidth:"100%",position:"relative",variants:{color:{default:{bg:"$border"},primary:{bg:"$primary"},secondary:{bg:"$secondary"},success:{bg:"$success"},warning:{bg:"$warning"},error:{bg:"$error"}}},defaultVariants:{color:"default"}}),M=(0,u.zo)("span",{position:"absolute",left:"50%",top:"50%",minHeight:"100%",display:"inline-flex",jc:"center",ai:"center",transform:"translate(-50%, -50%)",padding:"0 $lg",fontSize:"$base",fontWeight:"bold",textTransform:"capitalize",backgroundColor:"$background",zIndex:"$1",variants:{color:{default:{color:"$text"},primary:{color:"$primary"},secondary:{color:"$secondary"},success:{color:"$success"},warning:{color:"$warning"},error:{color:"$error"}}}}),W=({height:e,x:t,y:r,align:o,children:i,textColor:a,css:s,...c})=>{const l=(0,n.useMemo)((()=>o&&"center"!==o?"left"===o||"start"===o?{transform:"translateY(-50%)",left:"7%"}:{transform:"translateY(-50%)",left:"auto",right:"7%"}:""),[o]),u=r?(0,E.m)(r/2):0,d=t?(0,E.m)(t/2):0;return(0,b.jsx)(I,{role:"separator",css:{margin:`${u} ${d}`,height:`calc(${e} * 1px)`,...s},...c,children:i&&(0,b.jsx)(M,{css:{...l},color:a,className:"nextui-divider-text",children:i})})};W.toString=()=>".nextui-divider";const N=n.memo(W);var Z=(0,x.Z)(N,{x:0,y:0,height:1,align:"center"});v.Header=h,v.Body=p,v.Footer=m,v.Image=j,v.Divider=Z;var F=v},6979:function(e,t,r){r.d(t,{Z:function(){return g}});var n=r(7294),o=r(88),i=r(2903),a=r(3569),s=r(3917);const c=(0,r(6212).zo)("p",{variants:{weight:{hairline:{fontWeight:"$hairline"},thin:{fontWeight:"$thin"},light:{fontWeight:"$light"},normal:{fontWeight:"$normal"},medium:{fontWeight:"$medium"},semibold:{fontWeight:"$semibold"},bold:{fontWeight:"$bold"},extrabold:{fontWeight:"$extrabold"},black:{fontWeight:"$black"}}}});var l=r(5893);const u=n.forwardRef(((e,t)=>{const{children:r,tag:o,color:a,transform:u,margin:d,size:p,css:f,...h}=e,m=(0,i.gy)(t),g=(0,n.useMemo)((()=>(0,s.h1)(a)?"default"===a?"$text":`$${a}`:a),[a]),b=(0,n.useMemo)((()=>p?"number"==typeof p?`${p}px`:p:"inherit"),[p]),y=(0,n.useMemo)((()=>d?"number"==typeof d?`${p}px`:d:"inherit"),[d]);return(0,l.jsx)(c,{ref:m,as:o,css:{color:g,fontSize:p?b:"",margin:y,tt:u,...f},...h,children:r})}));a.Ts&&(u.displayName="NextUI.TextChild"),u.toString=()=>".nextui-text-child";const d=n.memo(u);var p=(0,o.Z)(d,{color:"default"});const f=(e,t,r,n)=>{if(!e.length)return t;const o=e.slice(1,e.length);return(0,l.jsx)(p,{tag:e[0],size:r,transform:n,children:f(o,t,r)})},h=n.forwardRef(((e,t)=>{const{h1:r,h2:o,h3:a,h4:s,h5:c,h6:u,b:d,small:h,i:m,span:g,del:b,em:y,blockquote:v,transform:x,size:k,margin:w,children:$,...S}=e,A=(0,i.gy)(t),C={h1:r,h2:o,h3:a,h4:s,h5:c,h6:u,blockquote:v},P={span:g,small:h,b:d,em:y,i:m,del:b},O=Object.keys(C).filter((e=>C[e])),z=Object.keys(P).filter((e=>P[e])),T=(0,n.useMemo)((()=>O[0]?O[0]:z[0]?z[0]:"p"),[O,z]),R=z.filter((e=>e!==T)),_=(0,n.useMemo)((()=>R.length?f(R,$,k,x):$),[R,$,k,x]);return(0,l.jsx)(p,{ref:A,transform:x,tag:T,margin:w,size:k,...S,children:_})}));a.Ts&&(h.displayName="NextUI.Text"),h.toString=()=>".nextui-text";const m=n.memo(h);var g=(0,o.Z)(m,{h1:!1,h2:!1,h3:!1,h4:!1,h5:!1,h6:!1,b:!1,small:!1,transform:"none",i:!1,span:!1,del:!1,em:!1,blockquote:!1,color:"default"})},6693:function(e,t,r){r.d(t,{Z:function(){return o}});var n=r(7294),o=(e,t=!0)=>{(0,n.useEffect)((()=>{const r=()=>e();return t&&r(),window.addEventListener("resize",r),()=>window.removeEventListener("resize",r)}),[])}},7568:function(e,t,r){function n(e,t,r,n,o,i,a){try{var s=e[i](a),c=s.value}catch(l){return void r(l)}s.done?t(c):Promise.resolve(c).then(n,o)}function o(e){return function(){var t=this,r=arguments;return new Promise((function(o,i){var a=e.apply(t,r);function s(e){n(a,o,i,s,c,"next",e)}function c(e){n(a,o,i,s,c,"throw",e)}s(void 0)}))}}r.d(t,{Z:function(){return o}})}}]); \ No newline at end of file diff --git a/dashboard/out/_next/static/chunks/framework-4556c45dd113b893.js b/dashboard/out/_next/static/chunks/framework-4556c45dd113b893.js new file mode 100644 index 0000000..1225f82 --- /dev/null +++ b/dashboard/out/_next/static/chunks/framework-4556c45dd113b893.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[774],{4448:function(e,n,t){var r=t(7294),l=t(3840);function a(e){for(var n="https://reactjs.org/docs/error-decoder.html?invariant="+e,t=1;t