diff --git a/.editorconfig b/.editorconfig index 72e85029ef6..c07643f1122 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,21 +2,11 @@ root = true [*] -indent_style = tab -end_of_line = lf charset = utf-8 -trim_trailing_whitespace = true +end_of_line = lf +indent_style = space insert_final_newline = true +trim_trailing_whitespace = true -[*.yml] -indent_style = space -indent_size = 2 - -[*.py] -indent_style = space - -[*.md] -trim_trailing_whitespace = false - -[Dockerfile] -indent_style = space +[*.{dm,json,md}] +indent_style = tab diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9dc03c27c7e..93617d90cdb 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -8,17 +8,18 @@ These are just guidelines, not rules, use your best judgment and feel free to pr #### Table Of Contents [What should I know before I get started?](#what-should-i-know-before-i-get-started) - * [Code of Conduct](#code-of-conduct) + +- [Code of Conduct](#code-of-conduct) [How Can I Contribute?](#how-can-i-contribute) - * [Your First Code Contribution](#your-first-code-contribution) - * [VOREStation Coding Standards](#vorestation-coding-standards) - * [Pull Requests](#pull-requests) - * [Git Commit Messages](#git-commit-messages) + +- [Your First Code Contribution](#your-first-code-contribution) +- [VOREStation Coding Standards](#vorestation-coding-standards) +- [Pull Requests](#pull-requests) +- [Git Commit Messages](#git-commit-messages) [Licensing](#Licensing) - ## What should I know before I get started? ### Code of Conduct @@ -36,23 +37,24 @@ Unsure where to begin contributing to VOREStation? You can start by looking thro Any code submissions that do not meet our coding standards are likely to be rejected, or at the very least, have a maintainer request changes on your PR. Save time and follow these standards from the start. -* Change whitespace as little as possible. Do not randomly add/remove whitespace. -* Map changes must be in tgm format. See the [Mapmerge2 Readme] for details, or use [StrongDMM] which can automatically save maps as tgm. +- Change whitespace as little as possible. Do not randomly add/remove whitespace. +- Map changes must be in tgm format. See the [Mapmerge2 Readme] for details, or use [StrongDMM] which can automatically save maps as tgm. ### Pull Requests -* Your submission must pass CI checking. The checks are important, prevent many common mistakes, and even experienced coders get caught by it sometimes. If you think there is a bug in CI, open an issue. (One known CI issue is comments in the middle of multi-line lists, just don't do it) -* Your PR should not have an excessive number of commits unless it is a large project or includes many separate remote commits. If you need to keep tweaking your PR to pass CI or to satisfy a maintainer's requests and are making many commits, you should squash them in the end and update your PR accordingly so these commits don't clog up the history. -* You can create a WIP PR, and if so, please mark it with [WIP] in the title **and make it a draft pr** so it can be labeled appropriately. These can't sit forever, though. -* If your pull request has many no-conflict merge commits ('merge from master' into your PR branch), it cannot be merged. Squash and make a new PR/forcepush to your PR branch. +- Your submission must pass CI checking. The checks are important, prevent many common mistakes, and even experienced coders get caught by it sometimes. If you think there is a bug in CI, open an issue. (One known CI issue is comments in the middle of multi-line lists, just don't do it) +- Your PR should not have an excessive number of commits unless it is a large project or includes many separate remote commits. If you need to keep tweaking your PR to pass CI or to satisfy a maintainer's requests and are making many commits, you should squash them in the end and update your PR accordingly so these commits don't clog up the history. +- You can create a WIP PR, and if so, please mark it with [WIP] in the title **and make it a draft pr** so it can be labeled appropriately. These can't sit forever, though. +- If your pull request has many no-conflict merge commits ('merge from master' into your PR branch), it cannot be merged. Squash and make a new PR/forcepush to your PR branch. ### Git Commit Messages -* Limit the first line to 72 characters or less, otherwise it truncates the title with '...', wrapping the rest into the description. -* Reference issues and pull requests liberally. -* Use the GitHub magic words "Fixed/Fixes/Fix, Resolved/Resolves/Resolve, Closed/Closes/Close", as in, "Closes #1928", as this will automatically close that issue when the PR is merged if it is a fix for that issue. +- Limit the first line to 72 characters or less, otherwise it truncates the title with '...', wrapping the rest into the description. +- Reference issues and pull requests liberally. +- Use the GitHub magic words "Fixed/Fixes/Fix, Resolved/Resolves/Resolve, Closed/Closes/Close", as in, "Closes #1928", as this will automatically close that issue when the PR is merged if it is a fix for that issue. ## Licensing + VOREStation is licensed under the GNU Affero General Public License version 3, which can be found in full in LICENSE-AGPL3.txt. Commits with a git authorship date prior to `1420675200 +0000` (2015/01/08 00:00) are licensed under the GNU General Public License version 3, which can be found in full in LICENSE-GPL3.txt. diff --git a/.github/ISSUE_TEMPLATE/0-feature.yml b/.github/ISSUE_TEMPLATE/0-feature.yml index d8adbbed9ca..b11425ae424 100644 --- a/.github/ISSUE_TEMPLATE/0-feature.yml +++ b/.github/ISSUE_TEMPLATE/0-feature.yml @@ -1,29 +1,29 @@ name: "✨ New feature" description: Suggest an idea for this codebase title: "✨ " -type: 'feature' -labels: ['Type: Feature/Suggestion'] +type: "feature" +labels: ["Type: Feature/Suggestion"] body: -- type: textarea - attributes: - label: Brief description of the feature - description: "Please provide a clear and concise description of what the feature should be." - validations: - required: true + - type: textarea + attributes: + label: Brief description of the feature + description: "Please provide a clear and concise description of what the feature should be." + validations: + required: true -- type: textarea - attributes: - label: What you want to happen - description: "Please use as much detail as possible when describing the feature behavior, including any context that might be relevant." - validations: - required: false + - type: textarea + attributes: + label: What you want to happen + description: "Please use as much detail as possible when describing the feature behavior, including any context that might be relevant." + validations: + required: false -- type: textarea - attributes: - label: Anything else you may wish to add - description: | - Location if it's a mapping issue, screenshots, sprites, etc. + - type: textarea + attributes: + label: Anything else you may wish to add + description: | + Location if it's a mapping issue, screenshots, sprites, etc. - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/1-bug_report.yml b/.github/ISSUE_TEMPLATE/1-bug_report.yml index 82ae8a0b68e..0553f226602 100644 --- a/.github/ISSUE_TEMPLATE/1-bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1-bug_report.yml @@ -1,56 +1,56 @@ name: General Bug description: Create a report to help us improve -title: '[GENERAL] <title>' -type: 'bug' -labels: 'Type: Bug' +title: "[GENERAL] <title>" +type: "bug" +labels: "Type: Bug" body: -- type: textarea - attributes: - label: Brief description of the bug - description: "Please provide a clear and concise description of what the bug is." - validations: - required: true + - type: textarea + attributes: + label: Brief description of the bug + description: "Please provide a clear and concise description of what the bug is." + validations: + required: true -- type: textarea - attributes: - label: What you expected to happen - description: "What normally happens when this occurs? Keep in mind that behavior may be different on other servers." - validations: - required: false + - type: textarea + attributes: + label: What you expected to happen + description: "What normally happens when this occurs? Keep in mind that behavior may be different on other servers." + validations: + required: false -- type: textarea - attributes: - label: What actually happened - description: "Please use as much detail as possible when describing the bug behavior, including any context (things you did before) that might be relevant." - validations: - required: false + - type: textarea + attributes: + label: What actually happened + description: "Please use as much detail as possible when describing the bug behavior, including any context (things you did before) that might be relevant." + validations: + required: false -- type: textarea - attributes: - label: Reproduction steps - description: "How do you trigger this bug? Please walk us through it step by step." - value: | - 1. - 2. - 3. - ... - render: bash - validations: - required: true + - type: textarea + attributes: + label: Reproduction steps + description: "How do you trigger this bug? Please walk us through it step by step." + value: | + 1. + 2. + 3. + ... + render: bash + validations: + required: true -- type: textarea - attributes: - label: Server Revision Info - description: "Copy-paste the entirety of the 'Show Server Revision' verb found under the OOC tab." - validations: - required: false + - type: textarea + attributes: + label: Server Revision Info + description: "Copy-paste the entirety of the 'Show Server Revision' verb found under the OOC tab." + validations: + required: false -- type: textarea - attributes: - label: Anything else you may wish to add - description: | - Location if it's a mapping issue, screenshots, sprites, etc. + - type: textarea + attributes: + label: Anything else you may wish to add + description: | + Location if it's a mapping issue, screenshots, sprites, etc. - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/2-ui_report.yml b/.github/ISSUE_TEMPLATE/2-ui_report.yml index 10673160864..137c2114c8b 100644 --- a/.github/ISSUE_TEMPLATE/2-ui_report.yml +++ b/.github/ISSUE_TEMPLATE/2-ui_report.yml @@ -1,42 +1,42 @@ name: UI Bug description: File a bug report, specific to any UI related things. -title: '[UI] <title>' -labels: 'Type: Bug' -type: 'bug' +title: "[UI] <title>" +labels: "Type: Bug" +type: "bug" body: -- type: textarea - attributes: - label: Brief description of the bug - description: "Please provide a clear and concise description of what the bug is." - validations: - required: true + - type: textarea + attributes: + label: Brief description of the bug + description: "Please provide a clear and concise description of what the bug is." + validations: + required: true -- type: textarea - attributes: - label: Reproduction steps - description: "How do you trigger this bug? Please walk us through it step by step." - value: | - 1. - 2. - 3. - ... - render: bash - validations: - required: true + - type: textarea + attributes: + label: Reproduction steps + description: "How do you trigger this bug? Please walk us through it step by step." + value: | + 1. + 2. + 3. + ... + render: bash + validations: + required: true -- type: textarea - attributes: - label: Server Revision Info - description: "Copy-paste the entirety of the 'Show Server Revision' verb found under the OOC tab." - validations: - required: false + - type: textarea + attributes: + label: Server Revision Info + description: "Copy-paste the entirety of the 'Show Server Revision' verb found under the OOC tab." + validations: + required: false -- type: textarea - attributes: - label: Anything else you may wish to add - description: | - Location if it's a mapping issue, screenshots, sprites, etc. + - type: textarea + attributes: + label: Anything else you may wish to add + description: | + Location if it's a mapping issue, screenshots, sprites, etc. - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/3-map_report.yml b/.github/ISSUE_TEMPLATE/3-map_report.yml index 7354a820d54..e5a9b523598 100644 --- a/.github/ISSUE_TEMPLATE/3-map_report.yml +++ b/.github/ISSUE_TEMPLATE/3-map_report.yml @@ -1,56 +1,56 @@ name: Map Bug description: Create a report, specific to any map related things. -title: '[MAPPING] <title>' -type: 'bug' -labels: ['Type: Bug', 'Type: Map'] +title: "[MAPPING] <title>" +type: "bug" +labels: ["Type: Bug", "Type: Map"] body: -- type: textarea - attributes: - label: Brief description of the bug - description: "Please provide a clear and concise description of what the bug is." - validations: - required: true + - type: textarea + attributes: + label: Brief description of the bug + description: "Please provide a clear and concise description of what the bug is." + validations: + required: true -- type: textarea - attributes: - label: What you expected to happen - description: "What normally happens when this occurs? Keep in mind that behavior may be different on other servers." - validations: - required: false + - type: textarea + attributes: + label: What you expected to happen + description: "What normally happens when this occurs? Keep in mind that behavior may be different on other servers." + validations: + required: false -- type: textarea - attributes: - label: What actually happened - description: "Please use as much detail as possible when describing the bug behavior, including any context (things you did before) that might be relevant." - validations: - required: false + - type: textarea + attributes: + label: What actually happened + description: "Please use as much detail as possible when describing the bug behavior, including any context (things you did before) that might be relevant." + validations: + required: false -- type: textarea - attributes: - label: Reproduction steps - description: "How do you trigger this bug? Please walk us through it step by step." - value: | - 1. - 2. - 3. - ... - render: bash - validations: - required: true + - type: textarea + attributes: + label: Reproduction steps + description: "How do you trigger this bug? Please walk us through it step by step." + value: | + 1. + 2. + 3. + ... + render: bash + validations: + required: true -- type: textarea - attributes: - label: Server Revision Info - description: "Copy-paste the entirety of the 'Show Server Revision' verb found under the OOC tab." - validations: - required: false + - type: textarea + attributes: + label: Server Revision Info + description: "Copy-paste the entirety of the 'Show Server Revision' verb found under the OOC tab." + validations: + required: false -- type: textarea - attributes: - label: Anything else you may wish to add - description: | - Location if it's a mapping issue, screenshots, sprites, etc. + - type: textarea + attributes: + label: Anything else you may wish to add + description: | + Location if it's a mapping issue, screenshots, sprites, etc. - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/.github/boring-cyborg.yml b/.github/boring-cyborg.yml index 9472efeeded..1fcf03a145e 100644 --- a/.github/boring-cyborg.yml +++ b/.github/boring-cyborg.yml @@ -6,36 +6,36 @@ labelPRBasedOnFilePath: # Add 'Type: Map' to any changes to .dmm files "Type: Map": - - '**/*.dmm' + - "**/*.dmm" # Add 'Type: Map' to any changes to image files "Type: Icon": - - '**/*.dmi' - - '**/*.png' - - '**/*.jpg' + - "**/*.dmi" + - "**/*.png" + - "**/*.jpg" # Add 'Type: Sound' to any change to sound files "Type: Sound": - - '**/*.ogg' - - '**/*.mp3' - - '**/*.wav' + - "**/*.ogg" + - "**/*.mp3" + - "**/*.wav" # Add 'Type: Fluff' to any change to *custom_items* "Type: Fluff": - - '**/*custom_items*' - - '**/*loadout_fluff*' - - 'config/alienwhitelist.txt' - - 'config/jobwhitelist.txt' - - 'config/custom_sprites.txt' + - "**/*custom_items*" + - "**/*loadout_fluff*" + - "config/alienwhitelist.txt" + - "config/jobwhitelist.txt" + - "config/custom_sprites.txt" # Contains changes to system folders "Type: .git or .github": - - '.github/**' - - '.git/**' - + - ".github/**" + - ".git/**" + # Contains changes to the TGUI bundle "Type: TGUI Bundle": - - 'tgui/public/**' + - "tgui/public/**" ##### Greetings ######################################################################################################## # Comment to be posted to welcome users when they open their first PR @@ -95,7 +95,7 @@ firstIssueWelcomeComment: > ###### PR/Branch Up-To-Date Checker #################################################################################### # Check if the branch is up to date with master when certain files are modified #checkUpToDate: -# # The default branch is "master", change the branch if you want to check against a different target branch +# # The default branch is "master", change the branch if you want to check against a different target branch # targetBranch: master # files: # # File paths that you want to check for diff --git a/.github/code_of_conduct.md b/.github/code_of_conduct.md index 06161256c88..0d17f66bae4 100644 --- a/.github/code_of_conduct.md +++ b/.github/code_of_conduct.md @@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo 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 +- 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 +- 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 diff --git a/.github/stale.yml b/.github/stale.yml index 7622dac94df..9cd3ffa6088 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -7,11 +7,11 @@ daysUntilClose: 30 # - pinned # - security # Label to use when marking an issue as stale -staleLabel: 'Status: No Response' +staleLabel: "Status: No Response" # Comment to post when marking an issue as stale. Set to `false` to disable 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. # Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false \ No newline at end of file +closeComment: false diff --git a/.github/workflows/autochangelog.yml b/.github/workflows/autochangelog.yml index f6ad147fbf3..3feaaf87c23 100644 --- a/.github/workflows/autochangelog.yml +++ b/.github/workflows/autochangelog.yml @@ -13,24 +13,24 @@ jobs: runs-on: ubuntu-latest if: github.event.pull_request.merged == true steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Checkout + uses: actions/checkout@v4 - - name: Generate App Token - id: app-token-generation - uses: actions/create-github-app-token@v2 - if: env.APP_PRIVATE_KEY != '' && env.APP_ID != '' - with: - app-id: ${{ secrets.APP_ID }} - private-key: ${{ secrets.APP_PRIVATE_KEY }} - env: - APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} - APP_ID: ${{ secrets.APP_ID }} + - name: Generate App Token + id: app-token-generation + uses: actions/create-github-app-token@v2 + if: env.APP_PRIVATE_KEY != '' && env.APP_ID != '' + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + env: + APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} + APP_ID: ${{ secrets.APP_ID }} - - name: Run auto changelog - uses: actions/github-script@v7 - with: - script: | - const { processAutoChangelog } = await import('${{ github.workspace }}/tools/pull_request_hooks/autoChangelog.js') - await processAutoChangelog({ github, context }) - github-token: ${{ steps.app-token-generation.outputs.token || secrets.GITHUB_TOKEN }} + - name: Run auto changelog + uses: actions/github-script@v7 + with: + script: | + const { processAutoChangelog } = await import('${{ github.workspace }}/tools/pull_request_hooks/autoChangelog.js') + await processAutoChangelog({ github, context }) + github-token: ${{ steps.app-token-generation.outputs.token || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a3b0fb7e60d..058a32d65a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - fetch-depth: 0 + fetch-depth: 0 # Caches - name: Setup Bun uses: ./.github/actions/setup_bun @@ -113,7 +113,7 @@ jobs: if: ( !contains(github.event.head_commit.message, '[ci skip]') ) strategy: matrix: - map: ['USE_MAP_TETHER', 'USE_MAP_STELLARDELIGHT', 'USE_MAP_GROUNDBASE'] + map: ["USE_MAP_TETHER", "USE_MAP_STELLARDELIGHT", "USE_MAP_GROUNDBASE"] # name: Integration Tests (${{ matrix.map }}) name: Integration Tests # needs: ['run_linters', 'dreamchecker'] @@ -170,7 +170,7 @@ jobs: tests_successful: if: ( !contains(github.event.head_commit.message, '[ci skip]') ) name: Integration Tests - needs: ['run_linters', 'dreamchecker', 'unit_tests', 'extra_map_tests'] + needs: ["run_linters", "dreamchecker", "unit_tests", "extra_map_tests"] runs-on: ubuntu-24.04 steps: - name: Report Success diff --git a/.github/workflows/compile_changelogs.yml b/.github/workflows/compile_changelogs.yml index 642ce2df676..83329b1c2de 100644 --- a/.github/workflows/compile_changelogs.yml +++ b/.github/workflows/compile_changelogs.yml @@ -2,7 +2,7 @@ name: Compile changelogs on: schedule: - - cron: "0 0 * * *" + - cron: "0 0 * * *" workflow_dispatch: jobs: @@ -23,7 +23,7 @@ jobs: #if: steps.value_holder.outputs.ACTIONS_ENABLED uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: "3.x" - name: "Install deps" #if: steps.value_holder.outputs.ACTIONS_ENABLED diff --git a/.github/workflows/remove_guide_comments.yml b/.github/workflows/remove_guide_comments.yml index 621d860c5cd..2c65239133f 100644 --- a/.github/workflows/remove_guide_comments.yml +++ b/.github/workflows/remove_guide_comments.yml @@ -8,11 +8,11 @@ jobs: remove_guide_comments: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Remove guide comments - uses: actions/github-script@v7 - with: - script: | - const { removeGuideComments } = await import('${{ github.workspace }}/tools/pull_request_hooks/removeGuideComments.js') - await removeGuideComments({ github, context }) + - name: Checkout + uses: actions/checkout@v4 + - name: Remove guide comments + uses: actions/github-script@v7 + with: + script: | + const { removeGuideComments } = await import('${{ github.workspace }}/tools/pull_request_hooks/removeGuideComments.js') + await removeGuideComments({ github, context }) diff --git a/.github/workflows/render_nanomaps.yml b/.github/workflows/render_nanomaps.yml index dcc33316e37..099d96e7773 100644 --- a/.github/workflows/render_nanomaps.yml +++ b/.github/workflows/render_nanomaps.yml @@ -3,13 +3,13 @@ # The file names and locations are VERY important here # DO NOT EDIT THIS UNLESS YOU KNOW WHAT YOU ARE DOING # -aa -name: 'Render Nanomaps' +name: "Render Nanomaps" on: push: branches: - master paths: - - 'maps/**' + - "maps/**" workflow_dispatch: permissions: {} @@ -19,51 +19,51 @@ jobs: contents: write # to push to branch pull-requests: write # to create pull requests (repo-sync/pull-request) - name: 'Generate NanoMaps' + name: "Generate NanoMaps" runs-on: ubuntu-24.04 steps: - - name: Clone - uses: actions/checkout@v4 + - name: Clone + uses: actions/checkout@v4 - - name: Branch - run: | - git fetch origin - git branch -f nanomaps_generation - git checkout nanomaps_generation - git reset --hard origin/master - - name: Restore SpacemanDMM cache - uses: actions/cache@v4 - with: - path: ~/SpacemanDMM - key: ${{ runner.os }}-spacemandmm-${{ hashFiles('dependencies.sh') }} - restore-keys: | - ${{ runner.os }}-spacemandmm- - - name: Install Tools - run: | - sudo apt update - bash tools/ci/install_spaceman_dmm.sh dmm-tools - sudo apt install -y imagemagick - - name: Ensure +x on github-actions directory - run: chmod -R +x ./tools/github-actions + - name: Branch + run: | + git fetch origin + git branch -f nanomaps_generation + git checkout nanomaps_generation + git reset --hard origin/master + - name: Restore SpacemanDMM cache + uses: actions/cache@v4 + with: + path: ~/SpacemanDMM + key: ${{ runner.os }}-spacemandmm-${{ hashFiles('dependencies.sh') }} + restore-keys: | + ${{ runner.os }}-spacemandmm- + - name: Install Tools + run: | + sudo apt update + bash tools/ci/install_spaceman_dmm.sh dmm-tools + sudo apt install -y imagemagick + - name: Ensure +x on github-actions directory + run: chmod -R +x ./tools/github-actions - - name: Generate Maps - run: tools/github-actions/nanomap-renderer-invoker.sh + - name: Generate Maps + run: tools/github-actions/nanomap-renderer-invoker.sh - - name: Commit Maps - run: | - git config --local user.email "action@github.com" - git config --local user.name "NanoMap Generation" - git add . - git commit -m "NanoMap Auto-Update (`date`)" -a || true - git push -f -u origin nanomaps_generation + - name: Commit Maps + run: | + git config --local user.email "action@github.com" + git config --local user.name "NanoMap Generation" + git add . + git commit -m "NanoMap Auto-Update (`date`)" -a || true + git push -f -u origin nanomaps_generation - - name: Create Pull Request - uses: repo-sync/pull-request@v2 - with: - source_branch: "nanomaps_generation" - destination_branch: "master" - pr_title: "Automatic NanoMap Update" - pr_body: "This pull request updates the nanomap images to the latest version of the map." - pr_label: "Infrastructure" - pr_allow_empty: false - github_token: ${{ secrets.GITHUB_TOKEN }} + - name: Create Pull Request + uses: repo-sync/pull-request@v2 + with: + source_branch: "nanomaps_generation" + destination_branch: "master" + pr_title: "Automatic NanoMap Update" + pr_body: "This pull request updates the nanomap images to the latest version of the map." + pr_label: "Infrastructure" + pr_allow_empty: false + github_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.prettierignore b/.prettierignore index 43eea47231b..bfb94bab391 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,6 +7,7 @@ juke **/build **/dist **/node_modules +html/templates # File names / types *.min.* diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 00000000000..ce6d6543462 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1 @@ +# This file is okay being empty as it will tell prettier to run in the repo diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 42b452ee258..9cbb34b3630 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,14 +1,14 @@ { - "recommendations": [ + "recommendations": [ "gbasood.byond-dm-language-support", "platymuus.dm-langclient", "stylemistake.auto-comment-blocks", "eamodio.gitlens", "oderwat.indent-rainbow", "rexebin.darkpurple-black", - "dbaeumer.vscode-eslint", "donkie.vscode-tgstation-test-adapter", "icrawl.discord-vscode", - "esbenp.prettier-vscode" + "esbenp.prettier-vscode", + "biomejs.biome" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 80b1d58f759..18ec2abd958 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,9 +1,9 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ { "type": "byond", "request": "launch", @@ -40,10 +40,7 @@ "request": "launch", "program": "${command:dreammaker.returnDreamDaemonPath}", "cwd": "${workspaceRoot}", - "args": [ - "${command:dreammaker.getFilenameDmb}", - "-trusted" - ], + "args": ["${command:dreammaker.getFilenameDmb}", "-trusted"], "preLaunchTask": "Build All" }, { @@ -52,11 +49,8 @@ "request": "launch", "program": "${command:dreammaker.returnDreamDaemonPath}", "cwd": "${workspaceRoot}", - "args": [ - "${command:dreammaker.getFilenameDmb}", - "-trusted" - ], + "args": ["${command:dreammaker.getFilenameDmb}", "-trusted"], "preLaunchTask": "Build All (low memory mode)" } - ] + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index ab1c3b2217e..d600dfc6af4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,73 +1,35 @@ { - "eslint.workingDirectories": ["./tgui"], - "workbench.editorAssociations": { - "*.dmi": "dmiEditor.dmiEditor" - }, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" + "editor.codeActionsOnSave": { + "source.fixAll.biome": "explicit" }, - "files.eol": "\n", - "files.encoding": "utf8", - "files.insertFinalNewline": true, - "files.trimFinalNewlines": true, - "files.trimTrailingWhitespace": true, - "files.associations": { - "*.{dme,dmf,dmm,dm}": "dm", - }, + "files.eol": "\n", + "files.encoding": "utf8", + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.trimTrailingWhitespace": true, + "editor.insertSpaces": false, "git.branchProtection": ["master"], - "gitlens.advanced.blame.customArguments": [ - "-w", "--ignore-revs-file", ".git-blame-ignore-revs" - ], - "search.exclude": { - "**/node_modules": true, - }, - "tgstationTestExplorer.project.resultsType": "json", - "[dm]": { - "files.eol": "\n", - "editor.detectIndentation": false, - "editor.insertSpaces": false - }, - "[markdown]": { - "files.trimTrailingWhitespace": false - }, - "[python]": { - "editor.detectIndentation": false, - "editor.insertSpaces": true, - "editor.tabSize": 4 - }, - "[yaml]": { - "editor.detectIndentation": false, - "editor.insertSpaces": true, - "editor.tabSize": 2 - }, - "[javascript]": { - "editor.rulers": [120], + "gitlens.advanced.blame.customArguments": ["-w"], + "tgstationTestExplorer.project.resultsType": "json", + "[javascript][typescript][javascriptreact][typescriptreact][css][json][jsonc]": { + "editor.defaultFormatter": "biomejs.biome", + "editor.formatOnSave": true, + "editor.rulers": [80] + }, + "[yaml][markdown][html][scss]": { "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[javascriptreact]": { - "editor.rulers": [120], - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[typescript]": { - "editor.rulers": [120], - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[typescriptreact]": { - "editor.rulers": [120], - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[scss]": { - "editor.rulers": [120], - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "debug.onTaskErrors": "abort", - "dreammaker.objectTreePane": true, - "dreammaker.autoUpdate": true, - "dreammaker.tickOnCreate": true, - "tgstationTestExplorer.project.DMEName": "tgmc.dme" + "editor.formatOnSave": true, + "editor.rulers": [80] + }, + "workbench.editorAssociations": { + "*.dmi": "dmiEditor.dmiEditor" + }, + "search.exclude": { + "**/node_modules": true + }, + "debug.onTaskErrors": "abort", + "dreammaker.objectTreePane": true, + "dreammaker.autoUpdate": true, + "dreammaker.tickOnCreate": true, + "tgstationTestExplorer.project.DMEName": "vorestation.dme" } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5efaf21e8fb..45a6cbb9dcb 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,11 +12,7 @@ "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build", "isDefault": true @@ -37,11 +33,7 @@ "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -61,11 +53,7 @@ "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -85,11 +73,7 @@ "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -109,11 +93,7 @@ "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -133,11 +113,7 @@ "DM_EXE": "${config:dreammaker.byondPath}" } }, - "problemMatcher": [ - "$dreammaker", - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$dreammaker", "$tsc", "$eslint-stylish"], "group": { "kind": "build" }, @@ -147,9 +123,7 @@ { "type": "dreammaker", "dme": "vorestation.dme", - "problemMatcher": [ - "$dreammaker" - ], + "problemMatcher": ["$dreammaker"], "group": "build", "label": "dm: build - vorestation.dme" }, @@ -164,10 +138,7 @@ "windows": { "command": ".\\bin\\tgui-build.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: build" }, @@ -177,10 +148,7 @@ "windows": { "command": ".\\bin\\tgui-dev.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: dev server" }, @@ -190,10 +158,7 @@ "windows": { "command": ".\\bin\\tgui-bench.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: bench" }, @@ -203,10 +168,7 @@ "windows": { "command": ".\\bin\\tgui-sonar.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: sonar" }, @@ -216,10 +178,7 @@ "windows": { "command": ".\\bin\\tgfont.cmd" }, - "problemMatcher": [ - "$tsc", - "$eslint-stylish" - ], + "problemMatcher": ["$tsc", "$eslint-stylish"], "group": "build", "label": "tgui: rebuild tgfont" } diff --git a/ATTRIBUTIONS.md b/ATTRIBUTIONS.md index f1e5784a1ea..ceaf2d56747 100644 --- a/ATTRIBUTIONS.md +++ b/ATTRIBUTIONS.md @@ -109,4 +109,4 @@ **Title:** Gooborgs<br> **Creator / Copyright:** Toriate<br> **License Holders:** Matica<br> -**License:** [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/)<br> \ No newline at end of file +**License:** [CC BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/)<br> diff --git a/README.md b/README.md index 28724e3d8ce..9a70c8bdcb5 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,14 @@ VOREStation is a fork of the Polaris code branch, itself a fork of the Baystatio --- ### LICENSE + The code for VOREStation is licensed under the [GNU Affero General Public License](http://www.gnu.org/licenses/agpl.html) version 3, which can be found in full in LICENSE-AGPL3.txt. Code with a git authorship date prior to `1420675200 +0000` (2015/01/08 00:00) are licensed under the GNU General Public License version 3, which can be found in full in LICENSE-GPL3.txt. All code whose authorship dates are not prior to `1420675200 +0000` is assumed to be licensed under AGPL v3, if you wish to license under GPL v3 please make this clear in the commit message and any added files. -If you wish to develop and host this codebase in a closed source manner you may use all code prior to `1420675200 +0000`, which is licensed under GPL v3. The major change here is that if you host a server using any code licensed under AGPLv3 you are required to provide full source code for your servers users as well including addons and modifications you have made. +If you wish to develop and host this codebase in a closed source manner you may use all code prior to `1420675200 +0000`, which is licensed under GPL v3. The major change here is that if you host a server using any code licensed under AGPLv3 you are required to provide full source code for your servers users as well including addons and modifications you have made. See [here](https://www.gnu.org/licenses/why-affero-gpl.html) for more information. @@ -38,11 +39,12 @@ All assets including icons and sound are under a [CC BY-SA 3.0](http://creativec Attributions and other licenses with links to original works are noted in [ATTRIBUTIONS.md](./ATTRIBUTIONS.md). ### GETTING THE CODE + The simplest way to obtain the code is using the github .zip feature. If you do this, you won't be able to make a Pull Request later, though. You'll need to use the git method. Click [here](https://github.com/VOREStation/VOREStation/archive/master.zip) to get the latest code as a .zip file, then unzip it to wherever you want. -The more complicated and easier to update method is using git. You'll need to download git or some client from [here](http://git-scm.com/). When that's installed, right click in any folder and click on "Git Bash". When that opens, type in: +The more complicated and easier to update method is using git. You'll need to download git or some client from [here](http://git-scm.com/). When that's installed, right click in any folder and click on "Git Bash". When that opens, type in: git clone https://github.com/VOREStation/VOREStation.git @@ -52,7 +54,7 @@ This will take a while to download, but it provides an easier method for updatin ### INSTALLATION -First-time installation should be fairly straightforward. First, you'll need BYOND installed. You can get it from [here](http://www.byond.com/). +First-time installation should be fairly straightforward. First, you'll need BYOND installed. You can get it from [here](http://www.byond.com/). **The quick way**. Find `bin/server.cmd` in this folder and double click it to automatically build and host the server on port 1337. @@ -60,17 +62,17 @@ First-time installation should be fairly straightforward. First, you'll need BY **Building vorestation in DreamMaker directly is deprecated and might produce errors**, such as `'tgui.bundle.js': cannot find file`. -If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong, or a code issue on the main repo. Ask on IRC. +If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong, or a code issue on the main repo. Ask on IRC. -Once that's done, open up the config folder. You'll want to edit config.txt to set the probabilities for different gamemodes in Secret and to set your server location so that all your players don't get disconnected at the end of each round. It's recommended you don't turn on the gamemodes with probability 0, as they have various issues and aren't currently being tested, so they may have unknown and bizarre bugs. +Once that's done, open up the config folder. You'll want to edit config.txt to set the probabilities for different gamemodes in Secret and to set your server location so that all your players don't get disconnected at the end of each round. It's recommended you don't turn on the gamemodes with probability 0, as they have various issues and aren't currently being tested, so they may have unknown and bizarre bugs. -You'll also want to edit admins.txt to remove the default admins and add your own. "Host" is the highest level of access, and the other recommended admin levels for now are "Game Admin" and "Moderator". The format is: +You'll also want to edit admins.txt to remove the default admins and add your own. "Host" is the highest level of access, and the other recommended admin levels for now are "Game Admin" and "Moderator". The format is: byondkey - Rank -where the BYOND key must be in lowercase and the admin rank must be properly capitalised. There are a bunch more admin ranks, but these two should be enough for most servers, assuming you have trustworthy admins. +where the BYOND key must be in lowercase and the admin rank must be properly capitalised. There are a bunch more admin ranks, but these two should be enough for most servers, assuming you have trustworthy admins. -Finally, to start the server, run Dream Daemon and enter the path to your compiled vorestation.dmb file. Make sure to set the port to the one you specified in the config.txt, and set the Security box to 'Trusted'. Then press GO and the server should start up and be ready to join. +Finally, to start the server, run Dream Daemon and enter the path to your compiled vorestation.dmb file. Make sure to set the port to the one you specified in the config.txt, and set the Security box to 'Trusted'. Then press GO and the server should start up and be ready to join. --- @@ -99,4 +101,4 @@ For a basic setup, simply copy every file from config/example to config. ### SQL Setup -The SQL backend for the library and stats tracking requires a MySQL server. Your server details go in /config/dbconfig.txt, and the SQL schema is in /SQL/tgstation_schema.sql. More detailed setup instructions arecoming soon, for now ask in our Discord. +The SQL backend for the library and stats tracking requires a MySQL server. Your server details go in /config/dbconfig.txt, and the SQL schema is in /SQL/tgstation_schema.sql. More detailed setup instructions arecoming soon, for now ask in our Discord. diff --git a/SECURITY.md b/SECURITY.md index a47f021db13..35be45b502b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,9 +10,9 @@ Please be as descriptive as possible! ## Older Libraries/Dependencies -Some of our libraries may not be used in a way that makes -them vulnerable, because we tend to only use a couple of -functions out of them. If that's the case and we think that -your vulnerability won't apply to our use-case, then -it may be closed, even if we're using an older version +Some of our libraries may not be used in a way that makes +them vulnerable, because we tend to only use a couple of +functions out of them. If that's the case and we think that +your vulnerability won't apply to our use-case, then +it may be closed, even if we're using an older version of the library. diff --git a/bin/tgui-bench.cmd b/bin/tgui-bench.cmd deleted file mode 100644 index 333115f7954..00000000000 --- a/bin/tgui-bench.cmd +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error tgui-bench %* -pause diff --git a/bin/tgui-fix.cmd b/bin/tgui-fix.cmd index f2844408ef8..9c5123bd76d 100644 --- a/bin/tgui-fix.cmd +++ b/bin/tgui-fix.cmd @@ -1,2 +1,2 @@ @echo off -call "%~dp0\..\tools\build\build.bat" --wait-on-error tgui-fix %* +call "%~dp0\..\tools\build\build.bat" --wait-on-error tgui-lint %* diff --git a/biome.json b/biome.json new file mode 100644 index 00000000000..81114a5cc9a --- /dev/null +++ b/biome.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.1.1/schema.json", + "assist": { + "actions": { + "source": { + "organizeImports": "on" + } + }, + "enabled": true + }, + "css": { + "formatter": { + "quoteStyle": "double" + } + }, + "files": { + "ignoreUnknown": false, + "includes": [ + "**", + "!**/node_modules", + "!tgui/public", + "tgui/public/tgui.html", + "!tgui/packages/tgui-setup/helpers.js" + ] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab", + "lineEnding": "lf" + }, + "javascript": { + "formatter": { + "indentStyle": "space", + "quoteStyle": "single" + } + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "a11y": "off", + "correctness": { + "noUnusedImports": "warn", + "noUnusedVariables": "off", + "useExhaustiveDependencies": "off", + "noUnusedFunctionParameters": "off", + "useHookAtTopLevel": "off" + }, + "security": { + "noDangerouslySetInnerHtml": "off" + }, + "style": { + "noNonNullAssertion": "off" + }, + "suspicious": { + "noArrayIndexKey": "off", + "noExplicitAny": "off", + "noImplicitAnyLet": "off", + "noAssignInExpressions": "warn" + } + } + }, + "vcs": { + "clientKind": "git", + "enabled": false, + "useIgnoreFile": false + } +} diff --git a/bun.lock b/bun.lock new file mode 100644 index 00000000000..d234ff9912a --- /dev/null +++ b/bun.lock @@ -0,0 +1,32 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "devDependencies": { + "@biomejs/biome": "^2.1.2", + "prettier": "^3.6.2", + }, + }, + }, + "packages": { + "@biomejs/biome": ["@biomejs/biome@2.1.2", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.1.2", "@biomejs/cli-darwin-x64": "2.1.2", "@biomejs/cli-linux-arm64": "2.1.2", "@biomejs/cli-linux-arm64-musl": "2.1.2", "@biomejs/cli-linux-x64": "2.1.2", "@biomejs/cli-linux-x64-musl": "2.1.2", "@biomejs/cli-win32-arm64": "2.1.2", "@biomejs/cli-win32-x64": "2.1.2" }, "bin": { "biome": "bin/biome" } }, "sha512-yq8ZZuKuBVDgAS76LWCfFKHSYIAgqkxVB3mGVVpOe2vSkUTs7xG46zXZeNPRNVjiJuw0SZ3+J2rXiYx0RUpfGg=="], + + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.1.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-leFAks64PEIjc7MY/cLjE8u5OcfBKkcDB0szxsWUB4aDfemBep1WVKt0qrEyqZBOW8LPHzrFMyDl3FhuuA0E7g=="], + + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.1.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-Nmmv7wRX5Nj7lGmz0FjnWdflJg4zii8Ivruas6PBKzw5SJX/q+Zh2RfnO+bBnuKLXpj8kiI2x2X12otpH6a32A=="], + + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-NWNy2Diocav61HZiv2enTQykbPP/KrA/baS7JsLSojC7Xxh2nl9IczuvE5UID7+ksRy2e7yH7klm/WkA72G1dw=="], + + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.1.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-qgHvafhjH7Oca114FdOScmIKf1DlXT1LqbOrrbR30kQDLFPEOpBG0uzx6MhmsrmhGiCFCr2obDamu+czk+X0HQ=="], + + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Km/UYeVowygTjpX6sGBzlizjakLoMQkxWbruVZSNE6osuSI63i4uCeIL+6q2AJlD3dxoiBJX70dn1enjQnQqwA=="], + + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.1.2", "", { "os": "linux", "cpu": "x64" }, "sha512-xlB3mU14ZUa3wzLtXfmk2IMOGL+S0aHFhSix/nssWS/2XlD27q+S6f0dlQ8WOCbYoXcuz8BCM7rCn2lxdTrlQA=="], + + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.1.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-G8KWZli5ASOXA3yUQgx+M4pZRv3ND16h77UsdunUL17uYpcL/UC7RkWTdkfvMQvogVsAuz5JUcBDjgZHXxlKoA=="], + + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.1.2", "", { "os": "win32", "cpu": "x64" }, "sha512-9zajnk59PMpjBkty3bK2IrjUsUHvqe9HWwyAWQBjGLE7MIBjbX2vwv1XPEhmO2RRuGoTkVx3WCanHrjAytICLA=="], + + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], + } +} diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index f2b893ad56b..871a0d610ba 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -425,7 +425,7 @@ GLOBAL_LIST_INIT(vr_mob_tf_options, list( "Frog" = /mob/living/simple_mob/vore/aggressive/frog, "Seagull" =/mob/living/simple_mob/vore/seagull, "Fox" = /mob/living/simple_mob/animal/passive/fox, - //"Racoon" = /mob/living/simple_mob/animal/passive/raccoon_ch, //TODO: Port from Downstream + "Racoon" = /mob/living/simple_mob/animal/passive/raccoon, "Shantak" = /mob/living/simple_mob/animal/sif/shantak, "Goose" = /mob/living/simple_mob/animal/space/goose, "Space shark" = /mob/living/simple_mob/animal/space/shark, @@ -488,7 +488,7 @@ GLOBAL_LIST_INIT(vr_mob_spawner_options, list( "Seagull" =/mob/living/simple_mob/vore/seagull, "Corgi" = /mob/living/simple_mob/animal/passive/dog/corgi, //"Armadillo" = /mob/living/simple_mob/animal/passive/armadillo, //TODO: Port from Downstream - //"Racoon" = /mob/living/simple_mob/animal/passive/raccoon_ch, //TODO: Port from Downstream + "Racoon" = /mob/living/simple_mob/animal/passive/raccoon, "Goose" = /mob/living/simple_mob/animal/space/goose, "Frog" = /mob/living/simple_mob/vore/aggressive/frog, "Dust jumper" = /mob/living/simple_mob/vore/alienanimals/dustjumper, diff --git a/code/controllers/subsystems/mobs.dm b/code/controllers/subsystems/mobs.dm index cf248b9749b..36043e9748f 100644 --- a/code/controllers/subsystems/mobs.dm +++ b/code/controllers/subsystems/mobs.dm @@ -121,14 +121,14 @@ SUBSYSTEM_DEF(mobs) var/podname = placeofdeath ? placeofdeath.name : "Unknown area" var/list/data = list( - "name" = L.real_name, - "byondkey" = L.key, - "job" = L.mind.assigned_role, - "special" = L.mind.special_role, + "name" = "[L.real_name]", + "byondkey" = "[L.key]", + "job" = "[L.mind.assigned_role]", + "special" = "[L.mind.special_role]", "pod" = podname, "tod" = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss"), - "laname" = L.lastattacker ? L.lastattacker:real_name : null, - "lakey" = L.lastattacker ? L.lastattacker:key : null, + "laname" = L.lastattacker ? L.lastattacker:real_name : "", + "lakey" = L.lastattacker ? L.lastattacker:key : "", "gender" = L.gender, "bruteloss" = L.getBruteLoss(), "fireloss" = L.getFireLoss(), diff --git a/code/controllers/subsystems/statpanel.dm b/code/controllers/subsystems/statpanel.dm index f00d1fa6ce6..0639d31400b 100644 --- a/code/controllers/subsystems/statpanel.dm +++ b/code/controllers/subsystems/statpanel.dm @@ -148,7 +148,7 @@ SUBSYSTEM_DEF(statpanels) var/atom/atom_icon = description_holders["icon"] var/shown_icon = target.examine_icon - if(!shown_icon) + if(!shown_icon && atom_icon) if(ismob(atom_icon) || length(atom_icon.overlays) > 0) var/force_south = FALSE if(isliving(atom_icon)) diff --git a/code/datums/components/COMPONENT_TEMPLATE.md b/code/datums/components/COMPONENT_TEMPLATE.md index 7b082058885..d458f597cc5 100644 --- a/code/datums/components/COMPONENT_TEMPLATE.md +++ b/code/datums/components/COMPONENT_TEMPLATE.md @@ -1,7 +1,6 @@ - # Template file for your new component -See _component.dm for detailed explanations +See \_component.dm for detailed explanations ```dm /datum/component/mycomponent diff --git a/code/datums/components/README.md b/code/datums/components/README.md index db8bf10a327..bb711e795d1 100644 --- a/code/datums/components/README.md +++ b/code/datums/components/README.md @@ -4,6 +4,6 @@ Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SendSignal()` call. Now every component that want's to can also know about this happening. -### [HackMD page for an introduction to the system as a whole.](https://hackmd.io/@tgstation/SignalsComponentsElements) +### [HackMD page for an introduction to the system as a whole.](https://hackmd.io/@tgstation/SignalsComponentsElements) -### See/Define signals and their arguments in [__DEFINES\components.dm](../../__DEFINES/components.dm) +### See/Define signals and their arguments in [\_\_DEFINES\components.dm](../../__DEFINES/components.dm) diff --git a/code/datums/elements/ELEMENT_TEMPLATE.md b/code/datums/elements/ELEMENT_TEMPLATE.md index 4bc1f72f2dc..33586bd94e5 100644 --- a/code/datums/elements/ELEMENT_TEMPLATE.md +++ b/code/datums/elements/ELEMENT_TEMPLATE.md @@ -1,7 +1,6 @@ - # Template file for your new element -See _element.dm for detailed explanations +See \_element.dm for detailed explanations ```dm /datum/element/myelement diff --git a/code/datums/elements/lootable/_lootable.dm b/code/datums/elements/lootable/_lootable.dm index 76e542d969b..5717091aa90 100644 --- a/code/datums/elements/lootable/_lootable.dm +++ b/code/datums/elements/lootable/_lootable.dm @@ -34,7 +34,7 @@ GLOBAL_LIST_INIT(unique_gamma_loot,list(\ UnregisterSignal(target, COMSIG_LOOT_REWARD) /// Calculates and drops loot, the source's turf is where it will be dropped, L is the searching mob, and searched_by is a passed list for storing who has searched a loot pile. -/datum/element/lootable/proc/loot(atom/source,mob/living/L,var/list/searched_by) +/datum/element/lootable/proc/loot(atom/source,mob/living/L,var/list/searched_by, wake_chance = 0) SIGNAL_HANDLER // The loot's all gone. if(loot_depletion && loot_left <= 0) @@ -91,6 +91,10 @@ GLOBAL_LIST_INIT(unique_gamma_loot,list(\ if("alium") final_message = span_alium(final_message) to_chat(L, span_info(final_message)) + var/disturbed_sleep = rand(1,100) //spawning of mobs, for now only the trash panda. + if(disturbed_sleep <= wake_chance) + new /mob/living/simple_mob/animal/passive/raccoon(get_turf(source)) + source.visible_message("A raccoon jumps out of the trash!.") // Check if we should delete on depletion if(!loot_depletion) diff --git a/code/game/objects/structures/trash_pile_vr.dm b/code/game/objects/structures/trash_pile_vr.dm index a08c2a8933b..da85d3cb920 100644 --- a/code/game/objects/structures/trash_pile_vr.dm +++ b/code/game/objects/structures/trash_pile_vr.dm @@ -128,7 +128,7 @@ hider = null to_chat(user,span_danger("Some sort of creature leaps out of \the [src]!")) else - SEND_SIGNAL(src,COMSIG_LOOT_REWARD,user,searchedby) + SEND_SIGNAL(src,COMSIG_LOOT_REWARD,user,searchedby, 5) busy = FALSE else return ..() diff --git a/code/js/view_variables.js b/code/js/view_variables.js index 86ca8cadc69..1b29528706a 100644 --- a/code/js/view_variables.js +++ b/code/js/view_variables.js @@ -1,33 +1,33 @@ function updateSearch() { - var filter_text = document.getElementById('filter'); - var filter = filter_text.value.toLowerCase(); + var filter_text = document.getElementById("filter"); + var filter = filter_text.value.toLowerCase(); - var vars_ol = document.getElementById('vars'); - var lis = vars_ol.children; - // the above line can be changed to vars_ol.getElementsByTagName("li") to filter child lists too - // potential todo: implement a per-admin toggle for this + var vars_ol = document.getElementById("vars"); + var lis = vars_ol.children; + // the above line can be changed to vars_ol.getElementsByTagName("li") to filter child lists too + // potential todo: implement a per-admin toggle for this - for(var i = 0; i < lis.length; i++) { - var li = lis[i]; - if(filter == "" || li.innerText.toLowerCase().indexOf(filter) != -1) { - li.style.display = "block"; - } else { - li.style.display = "none"; - } - } + for (var i = 0; i < lis.length; i++) { + var li = lis[i]; + if (filter == "" || li.innerText.toLowerCase().indexOf(filter) != -1) { + li.style.display = "block"; + } else { + li.style.display = "none"; + } + } } function selectTextField() { - var filter_text = document.getElementById('filter'); - filter_text.focus(); - filter_text.select(); + var filter_text = document.getElementById("filter"); + filter_text.focus(); + filter_text.select(); } function loadPage(list) { - if(list.options[list.selectedIndex].value == "") { - return; - } + if (list.options[list.selectedIndex].value == "") { + return; + } - location.href=list.options[list.selectedIndex].value; - list.selectedIndex = 0; + location.href = list.options[list.selectedIndex].value; + list.selectedIndex = 0; } diff --git a/code/modules/admin/verbs/adminfun.dm b/code/modules/admin/verbs/adminfun.dm index 9383ceb8d45..5bcbcfdec96 100644 --- a/code/modules/admin/verbs/adminfun.dm +++ b/code/modules/admin/verbs/adminfun.dm @@ -60,7 +60,7 @@ ADMIN_VERB(gib_them, (R_ADMIN|R_FUN), "Gib", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CA victim.gib() feedback_add_details("admin_verb","GIB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -ADMIN_VERB(gib_self, R_HOLDER, "Gibself", "Give yourself the same treatment you give others.", ADMIN_CATEGORY_FUN) +ADMIN_VERB(gib_self, R_HOLDER, "Gibself", "Give yourself the same treatment you give others.", "Fun.Do Not") var/confirm = tgui_alert(user, "You sure?", "Confirm", list("Yes", "No")) if(!confirm) return diff --git a/code/modules/asset_cache/readme.md b/code/modules/asset_cache/readme.md index 82e6bea896c..b2f8914708b 100644 --- a/code/modules/asset_cache/readme.md +++ b/code/modules/asset_cache/readme.md @@ -24,14 +24,12 @@ Call .get_url_mappings() to get an associated list with the urls your assets can See the documentation for `/datum/asset_transport` for the backend api the asset datums utilize. -The global variable `SSassets.transport` contains the currently configured transport. - - +The global variable `SSassets.transport` contains the currently configured transport. ### Notes: Because byond browse() calls use non-blocking queues, if your code uses output() (which bypasses all of these queues) to invoke javascript functions you will need to first have the javascript announce to the server it has loaded before trying to invoke js functions. -To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details. +To make your code work with any CDNs configured by the server, you must make sure assets are referenced from the url returned by `get_url_mappings()` or by asset_transport's `get_asset_url()`. (TGUI also has helpers for this.) If this can not be easily done, you can bypass the cdn using legacy assets, see the simple asset datum for details. CSS files that use url() can be made to use the CDN without needing to rewrite all url() calls in code by using the namespaced helper datum. See the documentation for `/datum/asset/simple/namespaced` for details. diff --git a/code/modules/asset_cache/validate_assets.html b/code/modules/asset_cache/validate_assets.html index 9728bb5c285..d55c8892cb1 100644 --- a/code/modules/asset_cache/validate_assets.html +++ b/code/modules/asset_cache/validate_assets.html @@ -1,29 +1,31 @@ -<!DOCTYPE html> +<!doctype html> <html lang="en"> - <head> - <meta http-equiv="X-UA-Compatible" content="IE=edge" /> - </head> - <body> - <script> - //this is used over window.location because window.location has a character limit in IE. - function sendbyond(text) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', '?'+text, true); - xhr.send(null); - } - var xhr = new XMLHttpRequest(); - xhr.open('GET', 'asset_data.json', true); - xhr.responseType = 'text'; - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - var status = xhr.status; - if (status >= 200 && status < 400) { - sendbyond('asset_cache_preload_data=' + encodeURIComponent(xhr.responseText)); - } - } - }; - xhr.send(null); - </script> - -</body> + <head> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + </head> + <body> + <script> + //this is used over window.location because window.location has a character limit in IE. + function sendbyond(text) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", "?" + text, true); + xhr.send(null); + } + var xhr = new XMLHttpRequest(); + xhr.open("GET", "asset_data.json", true); + xhr.responseType = "text"; + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + var status = xhr.status; + if (status >= 200 && status < 400) { + sendbyond( + "asset_cache_preload_data=" + + encodeURIComponent(xhr.responseText), + ); + } + } + }; + xhr.send(null); + </script> + </body> </html> diff --git a/code/modules/awaymissions/overmap_renamer/readme.md b/code/modules/awaymissions/overmap_renamer/readme.md index e370bbfaebb..eca39b34a03 100644 --- a/code/modules/awaymissions/overmap_renamer/readme.md +++ b/code/modules/awaymissions/overmap_renamer/readme.md @@ -1,4 +1,4 @@ -/* +/\* How to use - for mappers: @@ -7,8 +7,8 @@ How to use - for mappers: There, create a new object as given in the following example: /obj/effect/landmark/overmap_renamer/debris_field/examplelandmark - name = "Debris field example landmark that hints at which POI it came from!!!" - descriptors = list("This element appears when you hover over the obj in the nav console", "if someone manages to examine it", "This is what the printed paper says") + name = "Debris field example landmark that hints at which POI it came from!!!" + descriptors = list("This element appears when you hover over the obj in the nav console", "if someone manages to examine it", "This is what the printed paper says") Make sure you use exactly 3 elements, no more and no less and make sure each element is enclosed in a "". If you want to only change one element, fill in the other ones with the appropriate /obj/effect/overmap/visitable/ subtype's name, desc or scanner_desc your Z level corresponds to. @@ -21,7 +21,7 @@ How to use - for mappers: When making such landmarks: reserve them for MAJOR POIs - stuff a ship's scanner might pick up as having a significance. A small shuttle in the debris field shouldn't get a landmark The big alien derelict? Now that's worthy of a special landmark! - The idea of this system is for us to be able to treat existing Z levels as technically different locations. + The idea of this system is for us to be able to treat existing Z levels as technically different locations. Did you want to make an abandoned mining facility overmap adventure? Now this system will let you turn the DF into one (if the dice permits) Adding a new POI to a brand new lateloaded Z level (you can check which Z levels are handled by the renamer in code\controllers\subsystems\overmap_renamer_vr.dm) @@ -30,7 +30,7 @@ How to use - for mappers: Your task will become a bit more difficult now. Create a new .dm file following convention already estabilished with debrisfield_renamer.dm Within this file, define your /obj/effect/landmark/overmap_renamer/newname here - add the following line: + add the following line: var/static/reference //leave thus null. The initialization will change this to contain reference to your overmap object instance. Saves us from excess looping name = "obvious reference to the lateloaded Z in question here" Within this file, create a new /obj/effect/landmark/overmap_renamer/newname/Initialize() @@ -44,9 +44,6 @@ How to use - for mappers: change the if(D == "Debris Field") section in your new if statement just like you did for the landmark! And you're done! Refer to the "How to add a landmark" section on the top from now on. - - - Important procs, vars etc. contained within the following files: @@ -69,10 +66,9 @@ Important procs, vars etc. contained within the following files: /obj/effect/landmark/overmap_renamer/debris_field/Initialize() - Copy the entire thing, and change the "Debris Field" to your obj's var/unique_identifier code\controllers\subsystems\overmap_renamer_vr.dm - /datum/controller/subsystem/overmap_renamer/proc/update_names() - Checks which Z levels are loaded, modifies them + /datum/controller/subsystem/overmap_renamer/proc/update_names() - Checks which Z levels are loaded, modifies them To add new Z levels to the renamer, simply copy the if statement and its contents for debris field, taking care to change the "Debris Field - Z1 Space" to the name var defined in your lateloaded Z level's map_template datum example: maps\offmap_vr\common_offmaps.dm and then the /datum/map_template/common_lateload/away_debrisfield - -*/ +\*/ diff --git a/code/modules/client/preference_setup/loadout/02_loadout.dm b/code/modules/client/preference_setup/loadout/02_loadout.dm index c290a2ad0fc..b79d5738199 100644 --- a/code/modules/client/preference_setup/loadout/02_loadout.dm +++ b/code/modules/client/preference_setup/loadout/02_loadout.dm @@ -53,7 +53,7 @@ var/list/gear_datums = list() for(var/j in entries) entries["[j]"] = path2text_list(entries["[j]"]) pref.gear_list["[i]"] = entries - pref.gear_slot = save_data["gear_slot"] + pref.gear_slot = save_data["gear_slot"] || 1 /datum/category_item/player_setup_item/loadout/loadout/save_character(list/save_data) var/list/all_gear = list() diff --git a/code/modules/client/preferences/README.md b/code/modules/client/preferences/README.md index fabfb779c90..f822667968b 100644 --- a/code/modules/client/preferences/README.md +++ b/code/modules/client/preferences/README.md @@ -1,6 +1,6 @@ # Preferences (by Mothblocks) -This does not contain all the information on specific values--you can find those as doc-comments in relevant paths, such as `/datum/preference`. Rather, this gives you an overview for creating *most* preferences, and getting your foot in the door to create more advanced ones. +This does not contain all the information on specific values--you can find those as doc-comments in relevant paths, such as `/datum/preference`. Rather, this gives you an overview for creating _most_ preferences, and getting your foot in the door to create more advanced ones. ## Anatomy of a preference (A.K.A. how do I make one?) @@ -10,6 +10,7 @@ Most preferences consist of two parts: 2. A tgui representation in a TypeScript file. Every `/datum/preference` requires these three values be set: + 1. `category` - See [Categories](#Categories). 2. `savefile_key` - The value which will be saved in the savefile. This will also be the identifier for tgui. 3. `savefile_identifier` - Whether or not this is a character specific preference (`PREFERENCE_CHARACTER`) or one that affects the player (`PREFERENCE_PLAYER`). As an example: hair color is `PREFERENCE_CHARACTER` while your UI settings are `PREFERENCE_PLAYER`, since they do not change between characters. @@ -22,15 +23,15 @@ From here, you will want to write code resembling: import { Feature } from "../base"; export const savefile_key_here: Feature<T> = { - name: "Preference Name Here", - component: Component, + name: "Preference Name Here", + component: Component, - // Necessary for game preferences, unused for others - category: "CATEGORY", + // Necessary for game preferences, unused for others + category: "CATEGORY", - // Optional, shown as a tooltip - description: "This preference will blow your mind!", -} + // Optional, shown as a tooltip + description: "This preference will blow your mind!", +}; ``` `T` and `Component` depend on the type of preference you're making. Here are all common examples... @@ -59,9 +60,9 @@ Your `.tsx` file would look like: import { Feature, FeatureNumberInput } from "../base"; export const legs: Feature<number> = { - name: "Legs", - component: FeatureNumberInput, -} + name: "Legs", + component: FeatureNumberInput, +}; ``` ## Toggle preferences @@ -84,12 +85,13 @@ Your `.tsx` file would look like: import { CheckboxInput, FeatureToggle } from "../base"; export const enable_breathing: FeatureToggle = { - name: "Enable breathing", - component: CheckboxInput, -} + name: "Enable breathing", + component: CheckboxInput, +}; ``` ## Choiced preferences + A choiced preference is one where the only options are in a distinct few amount of choices. Examples include skin tone, shirt, and UI style. To create one, derive from `/datum/preference/choiced`. @@ -118,14 +120,15 @@ Your `.tsx` file would then look like: import { FeatureChoiced, FeatureDropdownInput } from "../base"; export const favorite_drink: FeatureChoiced = { - name: "Favorite drink", - component: FeatureDropdownInput, + name: "Favorite drink", + component: FeatureDropdownInput, }; ``` This will create a dropdown input for your preference. ### Choiced preferences - Icons + Choiced preferences can generate icons. This is how the clothing/species preferences work, for instance. However, if we just want a basic dropdown input with icons, it would look like this: ```dm @@ -155,12 +158,13 @@ Then, change your `.tsx` file to look like: import { FeatureChoiced, FeatureIconnedDropdownInput } from "../base"; export const favorite_drink: FeatureChoiced = { - name: "Favorite drink", - component: FeatureIconnedDropdownInput, + name: "Favorite drink", + component: FeatureIconnedDropdownInput, }; ``` ### Choiced preferences - Display names + Sometimes the values you want to save in code aren't the same as the ones you want to display. You can specify display names to change this. The only thing you will add is "compiled data". @@ -182,7 +186,8 @@ The only thing you will add is "compiled data". Your `.tsx` file does not change. The UI will figure it out for you! ## Color preferences -These refer to colors, such as your OOC color. When read, these values will be given as 6 hex digits, *without* the pound sign. + +These refer to colors, such as your OOC color. When read, these values will be given as 6 hex digits, _without_ the pound sign. ```dm /datum/preference/color/eyeliner_color @@ -197,12 +202,13 @@ Your `.tsx` file would look like: import { FeatureColorInput, Feature } from "../base"; export const eyeliner_color: Feature<string> = { - name: "Eyeliner color", - component: FeatureColorInput, + name: "Eyeliner color", + component: FeatureColorInput, }; ``` ## Name preferences + These refer to an alternative name. Examples include AI names and backup human names. These exist in `code/modules/client/preferences/names.dm`. @@ -255,6 +261,7 @@ If your preference is `PREFERENCE_CHARACTER`, it MUST override `apply_to_human`, You can also read preferences directly with `prefs.read_preference(/datum/preference/type/here)`, which will return the stored value. ## Categories + Every preference needs to be in a `category`. These can be found in `code/__DEFINES/preferences.dm`. ```dm @@ -306,7 +313,7 @@ Compiled data is sent to the `serverData` field in the `FeatureValueProps`. If you have good knowledge with tgui (especially TypeScript), you'll be able to create your own component to represent preferences. -The `component` field in a feature accepts __any__ component that accepts `FeatureValueProps<TReceiving, TSending = TReceiving, TServerData = undefined>`. +The `component` field in a feature accepts **any** component that accepts `FeatureValueProps<TReceiving, TSending = TReceiving, TServerData = undefined>`. This will give you the fields: @@ -335,18 +342,21 @@ For a basic example of how this can look, observe `CheckboxInput`: ```tsx export const CheckboxInput = ( - props: FeatureValueProps<BooleanLike, boolean> + props: FeatureValueProps<BooleanLike, boolean>, ) => { - return (<Button.Checkbox - checked={!!props.value} - onClick={() => { - props.handleSetValue(!props.value); - }} - />); + return ( + <Button.Checkbox + checked={!!props.value} + onClick={() => { + props.handleSetValue(!props.value); + }} + /> + ); }; ``` ## Advanced - Middleware + A `/datum/preference_middleware` is a way to inject your own data at specific points, as well as hijack actions. Middleware can hijack actions by specifying `action_delegations`: @@ -422,20 +432,20 @@ import { Antagonist, Category } from "../base"; import { multiline } from "common/string"; const Changeling: Antagonist = { - key: "changeling", // This must be the same as your filename - name: "Changeling", - description: [ - multiline` + key: "changeling", // This must be the same as your filename + name: "Changeling", + description: [ + multiline` A highly intelligent alien predator that is capable of altering their shape to flawlessly resemble a human. `, - multiline` + multiline` Transform yourself or others into different identities, and buy from an arsenal of biological weaponry with the DNA you collect. `, - ], - category: Category.Roundstart, // Category.Roundstart, Category.Midround, or Category.Latejoin + ], + category: Category.Roundstart, // Category.Roundstart, Category.Midround, or Category.Latejoin }; export default Changeling; @@ -453,4 +463,4 @@ If `antag_preference` is set, it will refer to that preference instead of `antag ## Updating special_roles -In `code/__DEFINES/role_preferences.dm` (the same place you'll need to make your ROLE_\* defined), simply add your antagonist to the `special_roles` assoc list. The key is your ROLE, the value is the number of days since your first game in order to play as that antagonist. +In `code/__DEFINES/role_preferences.dm` (the same place you'll need to make your ROLE\_\* defined), simply add your antagonist to the `special_roles` assoc list. The key is your ROLE, the value is the number of days since your first game in order to play as that antagonist. diff --git a/code/modules/keybindings/readme.md b/code/modules/keybindings/readme.md index 3f8b992b93d..c9ad3772e56 100644 --- a/code/modules/keybindings/readme.md +++ b/code/modules/keybindings/readme.md @@ -33,9 +33,9 @@ No client-set keybindings at this time, but it shouldn't be too hard if someone Notes about certain keys: -* `Tab` has client-sided behavior but acts normally -* `T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away. -* `\` needs to be escaped in the dmf so any usage is `\\` +- `Tab` has client-sided behavior but acts normally +- `T`, `O`, and `M` move focus to the input when pressed. This fires the keyUp macro right away. +- `\` needs to be escaped in the dmf so any usage is `\\` You cannot `TICK_CHECK` or check `world.tick_usage` inside of procs called by key down and up events. They happen outside of a byond tick and have no meaning there. Key looping diff --git a/code/modules/maint_recycler/code/vendor_datums/readme b/code/modules/maint_recycler/code/vendor_datums/readme index a8984f3bd45..cbc5778daa3 100644 --- a/code/modules/maint_recycler/code/vendor_datums/readme +++ b/code/modules/maint_recycler/code/vendor_datums/readme @@ -1,26 +1,26 @@ Adding something to the recycling vendor? Cool! Try and abide by the following design rules, though! -* Is it a "gamer tool" that directly helps with station round progression? Probably shouldn't have it! This includes things like diamonds, rare materials, etc. - (the materials that ARE in the vendor are the more "useless" ones, with the intended purpose of allowing people to get some materials for hangouts a bit easier if there's no cargo) - Steel and Glass are the exception here, because they're common enough that I don't really think people will use metacurrency to get meager amounts. obviously if that's not the case I'll tweak it. +- Is it a "gamer tool" that directly helps with station round progression? Probably shouldn't have it! This includes things like diamonds, rare materials, etc. + (the materials that ARE in the vendor are the more "useless" ones, with the intended purpose of allowing people to get some materials for hangouts a bit easier if there's no cargo) + Steel and Glass are the exception here, because they're common enough that I don't really think people will use metacurrency to get meager amounts. obviously if that's not the case I'll tweak it. -* is it recycleable? - If so - make sure it costs more than you can recycle it for. +- is it recycleable? + If so - make sure it costs more than you can recycle it for. -* Is it something that has huge potential to be annoying when used? - Things like Photon nades, voice changers, etc. While they COULD technically be classified as scene tools, in reality, it's just going to result in people being a PITA with them. we don't want to encourage that behaviour! +- Is it something that has huge potential to be annoying when used? + Things like Photon nades, voice changers, etc. While they COULD technically be classified as scene tools, in reality, it's just going to result in people being a PITA with them. we don't want to encourage that behaviour! Basically! does the hypothetical stock addition fall into any of these? if not, put a bit of thought into it! -* Scene tools. Stuff that has minimal impact on the game There's two subcategories of it. - * Stuff that explicitly can't interact with people without consent - NIF laws, capture crystals, etc. - * Stuff that has potential to. The various spicy chemicals, size guns, the various TF guns, etc. - Both of these should be good to go, but, you know. assume the worst. don't make a gas grenade with shrink chems. +- Scene tools. Stuff that has minimal impact on the game There's two subcategories of it. + - Stuff that explicitly can't interact with people without consent - NIF laws, capture crystals, etc. + - Stuff that has potential to. The various spicy chemicals, size guns, the various TF guns, etc. + Both of these should be good to go, but, you know. assume the worst. don't make a gas grenade with shrink chems. -* Mischief. Nothing overtly illegal or griefy, but stuff that'd otherwise be slightly inconvienent to get. - Insuls (for the hideout), and uhhh.... +- Mischief. Nothing overtly illegal or griefy, but stuff that'd otherwise be slightly inconvienent to get. + Insuls (for the hideout), and uhhh.... -* Rare stuff - Stuff that makes people go "awooga" and want to spend points on it, but can be achieved elsewhere. Stuff like NIFs, Bluespace harpoons, etc. Stuff you can already get on station, just a way to do so more consistently. Note that AT BEST these should be tied with the station version of the item. we still want people to go to science for 90% of the NIFs they get. +- Rare stuff + Stuff that makes people go "awooga" and want to spend points on it, but can be achieved elsewhere. Stuff like NIFs, Bluespace harpoons, etc. Stuff you can already get on station, just a way to do so more consistently. Note that AT BEST these should be tied with the station version of the item. we still want people to go to science for 90% of the NIFs they get. -* Showoff items. Stuff that makes other people go awooga. this shouldn't be anything actually useful. Just silly stuff akin to the fish hats. Golden tools, etc. +- Showoff items. Stuff that makes other people go awooga. this shouldn't be anything actually useful. Just silly stuff akin to the fish hats. Golden tools, etc. diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/_giant_spider.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/_giant_spider.dm index a4749ebdc16..75b124f87e9 100644 --- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/_giant_spider.dm +++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/_giant_spider.dm @@ -205,7 +205,7 @@ victim = L break - if(victim) + if(victim?.reagents) victim.reagents.add_reagent(REAGENT_ID_WARNINGTOXIN, poison_per_bite) victim.AdjustWeakened(2) victim.visible_message(span_danger("\The [src] has bitten \the [victim]!")) diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/passive/raccoon.dm b/code/modules/mob/living/simple_mob/subtypes/animal/passive/raccoon.dm new file mode 100644 index 00000000000..311c5638423 --- /dev/null +++ b/code/modules/mob/living/simple_mob/subtypes/animal/passive/raccoon.dm @@ -0,0 +1,58 @@ +//raccoon +/mob/living/simple_mob/animal/passive/raccoon + name = "raccoon" + desc = "A raccoon, also known as a trash panda." + tt_desc = "E purgamentum raccoonus" + icon = 'icons/mob/animal_vr.dmi' + icon_state = "raccoon" + item_state = "raccoon" + icon_living = "raccoon" + icon_dead = "raccoon_dead" + icon_rest = "raccoon_rest" + + ai_holder_type = /datum/ai_holder/simple_mob/passive/raccoon + say_list_type = /datum/say_list/raccoon + + see_in_dark = 6 + movement_cooldown = 3 + + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "kicks" + has_hands = TRUE + + min_oxy = 16 //Require atleast 16kPA oxygen + minbodytemp = 223 //Below -50 Degrees Celsius + maxbodytemp = 323 //Above 50 Degrees Celsius + + meat_amount = 1 + meat_type = /obj/item/reagent_containers/food/snacks/meat + + vore_active = TRUE + vore_capacity = 1 + vore_icons = SA_ICON_LIVING | SA_ICON_REST + center_offset = 0 + + species_sounds = "Raccoon" + pain_emote_1p = list("chitter") + pain_emote_3p = list("chitters") + +/mob/living/simple_mob/animal/passive/raccoon/Initialize(mapload) + . = ..() + ghostjoin = 1 + ghostjoin_icon() + GLOB.active_ghost_pods += src + +/mob/living/simple_mob/animal/passive/raccoon/Destroy() + GLOB.active_ghost_pods -= src + . = ..() + +/datum/say_list/raccoon + speak = list("HSSSSS") + emote_see = list("shakes their head", "shivers","grooms self", "nibbles on some trash") + emote_hear = list("purrs") + +/datum/ai_holder/simple_mob/passive/raccoon + flee_when_dying = TRUE + dying_threshold = 0.9 + speak_chance = 1 diff --git a/code/modules/reagents/readme.md b/code/modules/reagents/readme.md index ef274b6f9e6..b444112141d 100644 --- a/code/modules/reagents/readme.md +++ b/code/modules/reagents/readme.md @@ -1,306 +1,305 @@ -/* +/\* NOTE: IF YOU UPDATE THE REAGENT-SYSTEM, ALSO UPDATE THIS README. -Structure: /////////////////// ////////////////////////// - // Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents. - /////////////////// ////////////////////////// - | | - The object that holds everything. V - reagent_list var (list) A List of datums, each datum is a reagent. +Structure: /////////////////// ////////////////////////// +// Mob or object // -------> // Reagents var (datum) // Is a reference to the datum that holds the reagents. +/////////////////// ////////////////////////// +| | +The object that holds everything. V +reagent_list var (list) A List of datums, each datum is a reagent. - | | | - V V V - - reagents (datums) Reagents. I.e. Water , antitoxins or mercury. + | | | + V V V + reagents (datums) Reagents. I.e. Water , antitoxins or mercury. Random important notes: - An objects on_reagent_change will be called every time the objects reagents change. - Useful if you want to update the objects icon etc. + An objects on_reagent_change will be called every time the objects reagents change. + Useful if you want to update the objects icon etc. About the Holder: - The holder (reagents datum) is the datum that holds a list of all reagents - currently in the object.It also has all the procs needed to manipulate reagents + The holder (reagents datum) is the datum that holds a list of all reagents + currently in the object.It also has all the procs needed to manipulate reagents - Vars: - list/datum/reagent/reagent_list - List of reagent datums. + Vars: + list/datum/reagent/reagent_list + List of reagent datums. - total_volume - Total volume of all reagents. + total_volume + Total volume of all reagents. - maximum_volume - Maximum volume. + maximum_volume + Maximum volume. - atom/my_atom - Reference to the object that contains this. + atom/my_atom + Reference to the object that contains this. - Procs: + Procs: - get_free_space() - Returns the remaining free volume in the holder. + get_free_space() + Returns the remaining free volume in the holder. - get_master_reagent() - Returns the reference to the reagent with the largest volume + get_master_reagent() + Returns the reference to the reagent with the largest volume - get_master_reagent_name() - Ditto, but returns the name. + get_master_reagent_name() + Ditto, but returns the name. - get_master_reagent_id() - Ditto, but returns ID. + get_master_reagent_id() + Ditto, but returns ID. - update_total() - Updates total volume, called automatically. + update_total() + Updates total volume, called automatically. - handle_reactions() - Checks reagents and triggers any reactions that happen. Usually called automatically. + handle_reactions() + Checks reagents and triggers any reactions that happen. Usually called automatically. - add_reagent(var/id, var/amount, var/data = null, var/safety = 0) - Adds [amount] units of [id] reagent. [data] will be passed to reagent's mix_data() or initialize_data(). If [safety] is 0, handle_reactions() will be called. Returns 1 if successful, 0 otherwise. + add_reagent(var/id, var/amount, var/data = null, var/safety = 0) + Adds [amount] units of [id] reagent. [data] will be passed to reagent's mix_data() or initialize_data(). If [safety] is 0, handle_reactions() will be called. Returns 1 if successful, 0 otherwise. - remove_reagent(var/id, var/amount, var/safety = 0) - Ditto, but removes reagent. Returns 1 if successful, 0 otherwise. + remove_reagent(var/id, var/amount, var/safety = 0) + Ditto, but removes reagent. Returns 1 if successful, 0 otherwise. - del_reagent(var/id) - Removes all of the reagent. + del_reagent(var/id) + Removes all of the reagent. - has_reagent(var/id, var/amount = 0) - Checks if holder has at least [amount] of [id] reagent. Returns 1 if the reagent is found and volume is above [amount]. Returns 0 otherwise. + has_reagent(var/id, var/amount = 0) + Checks if holder has at least [amount] of [id] reagent. Returns 1 if the reagent is found and volume is above [amount]. Returns 0 otherwise. - clear_reagents() - Removes all reagents. + clear_reagents() + Removes all reagents. - get_reagent_amount(var/id) - Returns reagent volume. Returns 0 if reagent is not found. + get_reagent_amount(var/id) + Returns reagent volume. Returns 0 if reagent is not found. - get_data(var/id) - Returns get_data() of the reagent. + get_data(var/id) + Returns get_data() of the reagent. - get_reagents() - Returns a string containing all reagent ids and volumes, e.g. "carbon(4),nittrogen(5)". + get_reagents() + Returns a string containing all reagent ids and volumes, e.g. "carbon(4),nittrogen(5)". - remove_any(var/amount = 1) - Removes up to [amount] of reagents from [src]. Returns actual amount removed. + remove_any(var/amount = 1) + Removes up to [amount] of reagents from [src]. Returns actual amount removed. - trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) - Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]). If [copy] is 1, copies reagents instead. + trans_to_holder(var/datum/reagents/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + Transfers [amount] reagents from [src] to [target], multiplying them by [multiplier]. Returns actual amount removed from [src] (not amount transferred to [target]). If [copy] is 1, copies reagents instead. - touch(var/atom/target) - When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent. - This does not handle transferring reagents to things. - For example, splashing someone with water will get them wet and extinguish them if they are on fire, - even if they are wearing an impermeable suit that prevents the reagents from contacting the skin. - Basically just defers to touch_mob(target), touch_turf(target), or touch_obj(target), depending on target's type. - Not recommended to use this directly, since trans_to() calls it before attempting to transfer. + touch(var/atom/target) + When applying reagents to an atom externally, touch() is called to trigger any on-touch effects of the reagent. + This does not handle transferring reagents to things. + For example, splashing someone with water will get them wet and extinguish them if they are on fire, + even if they are wearing an impermeable suit that prevents the reagents from contacting the skin. + Basically just defers to touch_mob(target), touch_turf(target), or touch_obj(target), depending on target's type. + Not recommended to use this directly, since trans_to() calls it before attempting to transfer. - touch_mob(var/mob/target) - Calls each reagent's touch_mob(target). + touch_mob(var/mob/target) + Calls each reagent's touch_mob(target). - touch_turf(var/turf/target) - Calls each reagent's touch_turf(target). + touch_turf(var/turf/target) + Calls each reagent's touch_turf(target). - touch_obj(var/obj/target) - Calls each reagent's touch_obj(target). + touch_obj(var/obj/target) + Calls each reagent's touch_obj(target). - trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0) - The general proc for applying reagents to things externally (as opposed to directly injected into the contents). - It first calls touch, then the appropriate trans_to_*() or splash_mob(). - If for some reason you want touch effects to be bypassed (e.g. injecting stuff directly into a reagent container or person), call the appropriate trans_to_*() proc. - - Calls touch() before checking the type of [target], calling splash_mob(target, amount), trans_to_turf(target, amount, multiplier, copy), or trans_to_obj(target, amount, multiplier, copy). + trans_to(var/atom/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + The general proc for applying reagents to things externally (as opposed to directly injected into the contents). + It first calls touch, then the appropriate trans_to_*() or splash_mob(). + If for some reason you want touch effects to be bypassed (e.g. injecting stuff directly into a reagent container or person), call the appropriate trans_to_*() proc. - trans_id_to(var/atom/target, var/id, var/amount = 1) - Transfers [amount] of [id] to [target]. Returns amount transferred. + Calls touch() before checking the type of [target], calling splash_mob(target, amount), trans_to_turf(target, amount, multiplier, copy), or trans_to_obj(target, amount, multiplier, copy). - splash_mob(var/mob/target, var/amount = 1, var/clothes = 1) - Checks mob's clothing if [clothes] is 1 and transfers [amount] reagents to mob's skin. - Don't call this directly. Call apply_to() instead. + trans_id_to(var/atom/target, var/id, var/amount = 1) + Transfers [amount] of [id] to [target]. Returns amount transferred. - trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) - Transfers [amount] reagents to the mob's appropriate holder, depending on [type]. Ignores protection. + splash_mob(var/mob/target, var/amount = 1, var/clothes = 1) + Checks mob's clothing if [clothes] is 1 and transfers [amount] reagents to mob's skin. + Don't call this directly. Call apply_to() instead. - trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) - Turfs don't currently have any reagents. Puts [amount] reagents into a temporary holder, calls touch_turf(target) from it, and deletes it. + trans_to_mob(var/mob/target, var/amount = 1, var/type = CHEM_BLOOD, var/multiplier = 1, var/copy = 0) + Transfers [amount] reagents to the mob's appropriate holder, depending on [type]. Ignores protection. - trans_to_obj(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) - If target has reagents, transfers [amount] to it. Otherwise, same as trans_to_turf(). + trans_to_turf(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + Turfs don't currently have any reagents. Puts [amount] reagents into a temporary holder, calls touch_turf(target) from it, and deletes it. - atom/proc/create_reagents(var/max_vol) - Creates a new reagent datum. + trans_to_obj(var/turf/target, var/amount = 1, var/multiplier = 1, var/copy = 0) + If target has reagents, transfers [amount] to it. Otherwise, same as trans_to_turf(). + + atom/proc/create_reagents(var/max_vol) + Creates a new reagent datum. About Reagents: - Reagents are all the things you can mix and fille in bottles etc. This can be anything from - rejuvs over water to... iron. + Reagents are all the things you can mix and fille in bottles etc. This can be anything from + rejuvs over water to... iron. - Vars: + Vars: - name - Name that shows up in-game. + name + Name that shows up in-game. - id - ID that is used for internal tracking. MUST BE UNIQUE. + id + ID that is used for internal tracking. MUST BE UNIQUE. - description - Description that shows up in-game. + description + Description that shows up in-game. - datum/reagents/holder - Reference to holder. + datum/reagents/holder + Reference to holder. - reagent_state - Could be GAS, LIQUID, or SOLID. Affects nothing. Reserved for future use. + reagent_state + Could be GAS, LIQUID, or SOLID. Affects nothing. Reserved for future use. - list/data - Use varies by reagent. Custom variable. For example, blood stores blood group and viruses. + list/data + Use varies by reagent. Custom variable. For example, blood stores blood group and viruses. - volume - Current volume. + volume + Current volume. - metabolism - How quickly reagent is processed in mob's bloodstream; by default aslo affects ingest and touch metabolism. + metabolism + How quickly reagent is processed in mob's bloodstream; by default aslo affects ingest and touch metabolism. - ingest_met - How quickly reagent is processed when ingested; [metabolism] is used if zero. + ingest_met + How quickly reagent is processed when ingested; [metabolism] is used if zero. - touch_met - Ditto when touching. + touch_met + Ditto when touching. - dose - How much of the reagent has been processed, limited by [max_dose]. Used for reagents with varying effects (e.g. ethanol or rezadone) and overdosing. + dose + How much of the reagent has been processed, limited by [max_dose]. Used for reagents with varying effects (e.g. ethanol or rezadone) and overdosing. - max_dose - Maximum amount of reagent that has ever been in a mob. Exists so dose won't grow infinitely when small amounts of reagent are added over time. + max_dose + Maximum amount of reagent that has ever been in a mob. Exists so dose won't grow infinitely when small amounts of reagent are added over time. - overdose - If [dose] is bigger than [overdose], overdose() proc is called every tick. + overdose + If [dose] is bigger than [overdose], overdose() proc is called every tick. - scannable - If set to 1, will show up on health analyzers by name. + scannable + If set to 1, will show up on health analyzers by name. - affects_dead - If set to 1, will affect dead players. Used by Adminordrazine. + affects_dead + If set to 1, will affect dead players. Used by Adminordrazine. - glass_icon_state - Used by drinks. icon_state of the glass when this reagent is the master reagent. + glass_icon_state + Used by drinks. icon_state of the glass when this reagent is the master reagent. - glass_name - Ditto for glass name. + glass_name + Ditto for glass name. - glass_desc - Ditto for glass desciption. + glass_desc + Ditto for glass desciption. - glass_center_of_mass_x - glass_center_of_mass_y - Used for glass placement on tables. + glass_center_of_mass_x + glass_center_of_mass_y + Used for glass placement on tables. - color - "#RRGGBB" or "#RRGGBBAA" where A is alpha channel. + color + "#RRGGBB" or "#RRGGBBAA" where A is alpha channel. - color_weight - How much reagent affects color of holder. Used by paint. + color_weight + How much reagent affects color of holder. Used by paint. - Procs: + Procs: - remove_self(var/amount) - Removes [amount] of itself. + remove_self(var/amount) + Removes [amount] of itself. - touch_mob(var/mob/M) - Called when reagent is in another holder and not splashing the mob. Can be used with noncarbons. + touch_mob(var/mob/M) + Called when reagent is in another holder and not splashing the mob. Can be used with noncarbons. - touch_obj(var/obj/O) - How reagent reacts with objects. + touch_obj(var/obj/O) + How reagent reacts with objects. - touch_turf(var/turf/T) - How reagent reacts with turfs. + touch_turf(var/turf/T) + How reagent reacts with turfs. - on_mob_life(var/mob/living/carbon/M, var/alien, var/location) - Makes necessary checks and calls one of affect procs. + on_mob_life(var/mob/living/carbon/M, var/alien, var/location) + Makes necessary checks and calls one of affect procs. - affect_blood(var/mob/living/carbon/M, var/alien, var/removed) - How reagent affects mob when injected. [removed] is the amount of reagent that has been removed this tick. [alien] is the mob's reagent flag. + affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + How reagent affects mob when injected. [removed] is the amount of reagent that has been removed this tick. [alien] is the mob's reagent flag. - affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) - Ditto, ingested. Defaults to affect_blood with halved dose. + affect_ingest(var/mob/living/carbon/M, var/alien, var/removed) + Ditto, ingested. Defaults to affect_blood with halved dose. - affect_touch(var/mob/living/carbon/M, var/alien, var/removed) - Ditto, touching. + affect_touch(var/mob/living/carbon/M, var/alien, var/removed) + Ditto, touching. - overdose(var/mob/living/carbon/M, var/alien) - Called when dose is above overdose. Defaults to M.adjustToxLoss(REM). + overdose(var/mob/living/carbon/M, var/alien) + Called when dose is above overdose. Defaults to M.adjustToxLoss(REM). - initialize_data(var/newdata) - Called when reagent is created. Defaults to setting [data] to [newdata]. + initialize_data(var/newdata) + Called when reagent is created. Defaults to setting [data] to [newdata]. - mix_data(var/newdata, var/newamount) - Called when [newamount] of reagent with [newdata] data is added to the current reagent. Used by paint. + mix_data(var/newdata, var/newamount) + Called when [newamount] of reagent with [newdata] data is added to the current reagent. Used by paint. - get_data() - Returns data. Can be overriden. + get_data() + Returns data. Can be overriden. About Recipes: - Recipes are simple datums that contain a list of required reagents and a result. - They also have a proc that is called when the recipe is matched. + Recipes are simple datums that contain a list of required reagents and a result. + They also have a proc that is called when the recipe is matched. - Vars: + Vars: - name - Name of the reaction, currently unused. + name + Name of the reaction, currently unused. - id - ID of the reaction, must be unique. + id + ID of the reaction, must be unique. - result - ID of the resulting reagent. Can be null. + result + ID of the resulting reagent. Can be null. - list/required_reagents - Reagents that are required for the reaction and are used up during it. + list/required_reagents + Reagents that are required for the reaction and are used up during it. - list/catalysts - Ditto, but not used up. + list/catalysts + Ditto, but not used up. - list/inhibitors - Opposite, prevent the reaction from happening. + list/inhibitors + Opposite, prevent the reaction from happening. - result_amount - Amount of resulting reagent. + result_amount + Amount of resulting reagent. - mix_message - Message that is shown to mobs when reaction happens. + mix_message + Message that is shown to mobs when reaction happens. - Procs: + Procs: - can_happen(var/datum/reagents/holder) - Customizable. If it returns 0, reaction will not happen. Defaults to always returning 1. Used by slime core reactions. + can_happen(var/datum/reagents/holder) + Customizable. If it returns 0, reaction will not happen. Defaults to always returning 1. Used by slime core reactions. - on_reaction(var/datum/reagents/holder, var/created_volume) - Called when reaction happens. Used by explosives. + on_reaction(var/datum/reagents/holder, var/created_volume) + Called when reaction happens. Used by explosives. - send_data(var/datum/reagents/T) - Sets resulting reagent's data. Used by blood paint. + send_data(var/datum/reagents/T) + Sets resulting reagent's data. Used by blood paint. About the Tools: - By default, all atom have a reagents var - but its empty. if you want to use an object for the chem. - system you'll need to add something like this in its new proc: + By default, all atom have a reagents var - but its empty. if you want to use an object for the chem. + system you'll need to add something like this in its new proc: - atom/proc/create_reagents(var/max_volume) + atom/proc/create_reagents(var/max_volume) - Other important stuff: + Other important stuff: - amount_per_transfer_from_this var - This var is mostly used by beakers and bottles. - It simply tells us how much to transfer when - 'pouring' our reagents into something else. + amount_per_transfer_from_this var + This var is mostly used by beakers and bottles. + It simply tells us how much to transfer when + 'pouring' our reagents into something else. - atom/proc/is_open_container() - Checks atom/var/flags & OPENCONTAINER. - If this returns 1 , you can use syringes, beakers etc - to manipulate the contents of this object. - If it's 0, you'll need to write your own custom reagent - transfer code since you will not be able to use the standard - tools to manipulate it. + atom/proc/is_open_container() + Checks atom/var/flags & OPENCONTAINER. + If this returns 1 , you can use syringes, beakers etc + to manipulate the contents of this object. + If it's 0, you'll need to write your own custom reagent + transfer code since you will not be able to use the standard + tools to manipulate it. -*/ +\*/ diff --git a/code/modules/shuttles/upgrade_guide.md b/code/modules/shuttles/upgrade_guide.md index 7c2c73f422e..4e7275b4a63 100644 --- a/code/modules/shuttles/upgrade_guide.md +++ b/code/modules/shuttles/upgrade_guide.md @@ -1,35 +1,37 @@ # "Landmark" Shuttles Conversion + This guide helps with updating maps and shuttle datums from the old "area" based system to the "landmark" based system. ## Summary -The old shuttle datum worked with areas (`/area`). You are probably familiar with every shuttle having a few cookie-cutter shaped areas it travels between. + +The old shuttle datum worked with areas (`/area`). You are probably familiar with every shuttle having a few cookie-cutter shaped areas it travels between. When the shuttle "moved" it was translated from its current area to the destination area. The areas had to be _exactly_ the same shape so -that each turf in the origin area got translated to the equivalent place at the target.\ +that each turf in the origin area got translated to the equivalent place at the target.\ Since _all possible_ destinations had to have a dedicated area (and areas in BYOND can't overlap) this means it is impossible for two shuttles to travel to the same spot, even at different times. In the new system shuttle destinations are represented by "landmark" objects (`/obj/effect/shuttle_landmark`). When a shuttle is "moved" it is translated from its current landmark to the destination landmark, with each turf keeping its same position _relative_ to the landmarks. -In other words, whatever a turf's x/y/z offsets are from the origin landmark, it will be moved to the same x/y/z offset from the destination landmark. +In other words, whatever a turf's x/y/z offsets are from the origin landmark, it will be moved to the same x/y/z offset from the destination landmark. ## Landmark Objects + Shuttle destinations are represented by `/obj/effect/shuttle_landmark` objects on the map. -* `name` - Pretty name of the nav point, used on overmap and in messages and console UI. -* `landmark_tag` - Globally unique ID, used by everything else to refer to this landmark. -* `docking_controller` - ID of the controller on the dock side (initialize to id_tag, becomes reference). Leave null if not applicable. -* `base_area` - Type path of the `/area` that should be here when a shuttle is *not* present. -* `base_turf` - Type path of the `/turf` that should be here when a shuttle is *not* present. -* `shuttle_restricted` - If not null, only the named shuttle is allowed to use this landmark. (TODO: Overmap functionality) -* `flags` - Bitfield - defaults to `SLANDMARK_FLAG_AUTOSET`, can be any combination of: - * `SLANDMARK_FLAG_AUTOSET` (1) - If set, will initialize base_area and base_turf to same as where it was spawned at. - * `SLANDMARK_FLAG_ZERO_G` (2) - If set, Zero-G shuttles moved here will lose gravity unless the area has ambient gravity. -* `special_dock_targets` - Used to configure shuttles with multiple docking controllers on the shuttle. Map of shuttle `name` -> `id_tag` of the docking controller it should use for this landmark. (Think of a shuttle with airlocks on both sides, each with their own controller. This would tell it which side to use.) - +- `name` - Pretty name of the nav point, used on overmap and in messages and console UI. +- `landmark_tag` - Globally unique ID, used by everything else to refer to this landmark. +- `docking_controller` - ID of the controller on the dock side (initialize to id_tag, becomes reference). Leave null if not applicable. +- `base_area` - Type path of the `/area` that should be here when a shuttle is _not_ present. +- `base_turf` - Type path of the `/turf` that should be here when a shuttle is _not_ present. +- `shuttle_restricted` - If not null, only the named shuttle is allowed to use this landmark. (TODO: Overmap functionality) +- `flags` - Bitfield - defaults to `SLANDMARK_FLAG_AUTOSET`, can be any combination of: + - `SLANDMARK_FLAG_AUTOSET` (1) - If set, will initialize base_area and base_turf to same as where it was spawned at. + - `SLANDMARK_FLAG_ZERO_G` (2) - If set, Zero-G shuttles moved here will lose gravity unless the area has ambient gravity. +- `special_dock_targets` - Used to configure shuttles with multiple docking controllers on the shuttle. Map of shuttle `name` -> `id_tag` of the docking controller it should use for this landmark. (Think of a shuttle with airlocks on both sides, each with their own controller. This would tell it which side to use.) ## Shuttle Types - ### Ferry Shuttles + These shuttles go back and forth between two locations (normally called "station" and "offsite"). Examples: Mining shuttle, Arrivals Shuttle, etc. @@ -38,24 +40,22 @@ New Type Path: `/datum/shuttle/autodock/ferry` ##### New Vars: -Name|Type|Required?|Info ----|---|---|--- -shuttle_area |`/area` typepath(s)|Yes| Can be a single path or list of paths. +| Name | Type | Required? | Info | +| ------------ | ------------------- | --------- | -------------------------------------- | +| shuttle_area | `/area` typepath(s) | Yes | Can be a single path or list of paths. | ##### Replaced vars: -Old|New|Required?|Info -:---:|:---:|:---:|--- -area_station |landmark_station |Yes|Tag of the landmark for the "station" location. -area_offsite |landmark_offsite |Yes|Tag of the landmark for the "offsite" location. -area_transition |landmark_transition |No|Tag of the landmark for the "transition" location used during long_jump() -dock_target_station |On landmark |No|`id_tag` docking controller *on the dock* has been moved to the `docking_controller` var on the landmark_station landmark obj. -dock_target_offsite |On landmark |No|`id_tag` docking controller *on the dock* has been moved to the `docking_controller` var on the landmark_offsite landmark obj. - - - +| Old | New | Required? | Info | +| :-----------------: | :-----------------: | :-------: | ------------------------------------------------------------------------------------------------------------------------------ | +| area_station | landmark_station | Yes | Tag of the landmark for the "station" location. | +| area_offsite | landmark_offsite | Yes | Tag of the landmark for the "offsite" location. | +| area_transition | landmark_transition | No | Tag of the landmark for the "transition" location used during long_jump() | +| dock_target_station | On landmark | No | `id_tag` docking controller _on the dock_ has been moved to the `docking_controller` var on the landmark_station landmark obj. | +| dock_target_offsite | On landmark | No | `id_tag` docking controller _on the dock_ has been moved to the `docking_controller` var on the landmark_offsite landmark obj. | ### Multi Shuttles + These shuttles go between a list of configured locations, one of which is its starting location. Examples: Skipjack, Syndicate Shuttle @@ -64,61 +64,64 @@ New Type Path: `/datum/shuttle/autodock/multi` ##### New Vars: -Name|Type|Required?|Info ----|---|---|--- -shuttle_area |`/area` typepath(s)|Yes| Can be a single path or list of paths. +| Name | Type | Required? | Info | +| ------------ | ------------------- | --------- | -------------------------------------- | +| shuttle_area | `/area` typepath(s) | Yes | Can be a single path or list of paths. | ##### Replaced vars: -Old|New|Required?|Info -:---:|:---:|:---:|--- -origin |current_location |Yes|Tag of the landmark where the shuttle is at startup. -interim |landmark_transition |No|Tag of the landmark for the "transition" location used during long_jump() -start_location |N/A |No|No longer necessary, automatically determined from the value of `origin` -destinations |destination_tags |Yes|List of destinations the shuttle can travel to. Used to be associative list of *name* -> *area typepath*, now is normal list of landmark tag ids. Name is now read from the landmark obj. -destination_dock_targets|On landmarks |No|Used to be associative list of *name* -> *id_tag* for which docking controller *on the dock* to use at each destination. This is now specified by the `docking_controller` var on each landmark obj. - - +| Old | New | Required? | Info | +| :----------------------: | :-----------------: | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| origin | current_location | Yes | Tag of the landmark where the shuttle is at startup. | +| interim | landmark_transition | No | Tag of the landmark for the "transition" location used during long_jump() | +| start_location | N/A | No | No longer necessary, automatically determined from the value of `origin` | +| destinations | destination_tags | Yes | List of destinations the shuttle can travel to. Used to be associative list of _name_ -> _area typepath_, now is normal list of landmark tag ids. Name is now read from the landmark obj. | +| destination_dock_targets | On landmarks | No | Used to be associative list of _name_ -> _id_tag_ for which docking controller _on the dock_ to use at each destination. This is now specified by the `docking_controller` var on each landmark obj. | ### Web Shuttles -These shuttles travel along a network of locations connected by routes. Instead of being able to travel to any of its destinations, it can only travel to destinations connected by a route to its current location. Added by Polaris as an upgrade to Multi Shuttles. + +These shuttles travel along a network of locations connected by routes. Instead of being able to travel to any of its destinations, it can only travel to destinations connected by a route to its current location. Added by Polaris as an upgrade to Multi Shuttles. Note: While cool, it is likely that the upcoming "overmap" shuttles will be even cooler, and may eventually replace some web shuttles. -Examples: Southern Cross' Ninja Shuttle, Tether's Excursion Shuttle +Examples: Southern Cross' Ninja Shuttle, Tether's Excursion Shuttle Old Type Path: `/datum/shuttle/web_shuttle`\ New Type Path: `/datum/shuttle/autodock/web_shuttle` ##### New Vars: -Name|Type|Required?|Info ----|---|---|--- -shuttle_area |`/area` typepath(s)|Yes| Can be a single path or list of paths. +| Name | Type | Required? | Info | +| ------------ | ------------------- | --------- | -------------------------------------- | +| shuttle_area | `/area` typepath(s) | Yes | Can be a single path or list of paths. | ##### Replaced vars: -Old|New|Required?|Info -:---:|:---:|:---:|--- -current_area |current_location |Yes|Tag of the landmark where the shuttle is at startup. +| Old | New | Required? | Info | +| :----------: | :--------------: | :-------: | ---------------------------------------------------- | +| current_area | current_location | Yes | Tag of the landmark where the shuttle is at startup. | #### Web Destination Configuration (`/datum/shuttle_destination`) -The network of routes for each web shuttle is configured by defining datums. These are mostly unchanged but use landmarks instead of areas now. + +The network of routes for each web shuttle is configured by defining datums. These are mostly unchanged but use landmarks instead of areas now. ##### Replaced vars: -Old|New|Required?|Info -:---:|:---:|:---:|--- -my_area |my_landmark |Yes|Tag of the landmark associated with this destination. -preferred_interim_area |preferred_interim_tag |No|Tag of the landmark for the "transition" location used during long_jump() -dock_target |On landmark |No|`id_tag` docking controller *on the dock* has been moved to the `docking_controller` var on the my_landmark landmark obj. +| Old | New | Required? | Info | +| :--------------------: | :-------------------: | :-------: | ------------------------------------------------------------------------------------------------------------------------- | +| my_area | my_landmark | Yes | Tag of the landmark associated with this destination. | +| preferred_interim_area | preferred_interim_tag | No | Tag of the landmark for the "transition" location used during long_jump() | +| dock_target | On landmark | No | `id_tag` docking controller _on the dock_ has been moved to the `docking_controller` var on the my_landmark landmark obj. | ### Misc Shuttle Types + Other shuttle types that are either unused or unchanged in particular. #### Escape Pods + Special case of ferry shuttles that use escape pod berth controllers. -Type path changed from `/datum/shuttle/ferry/escape_pod` to `/datum/shuttle/autodock/ferry/escape_pod` +Type path changed from `/datum/shuttle/ferry/escape_pod` to `/datum/shuttle/autodock/ferry/escape_pod` Follow same instructions as for other ferry shuttles. #### Multidock Ferry Shuttles + `/datum/shuttle/ferry/multidock` was a variant of ferry shuttles that could use a different docking port at each location. Obsolete since is now natively supported by all dockable shuttles. diff --git a/code/modules/tgchat/README.md b/code/modules/tgchat/README.md index 71acb47c458..d2a99e5ffd2 100644 --- a/code/modules/tgchat/README.md +++ b/code/modules/tgchat/README.md @@ -5,6 +5,7 @@ ### Message Format TgChat handles sending messages from the server to the client through the use of JSON payloads, of which the format will change depending on the type of message and the intended client endpoint. An example of the payload for chat messages is as follows: + ```json { "sequence": 0, @@ -13,13 +14,13 @@ TgChat handles sending messages from the server to the client through the use of "text": ". . .", // ?optional !atleast-one "html": ". . .", // ?optional !atleast-one "avoidHighlighting": 0 // ?optional - }, + } } ``` ### Reliability -In the past there have been issues where BYOND will silently and without reason lose a message we sent to the client, to detect this and recover from it seamlessly TgChat also has a baked in reliability layer. This reliability layer is very primitive, and simply keeps track of received sequence numbers. Should the client receive an unexpected sequence number TgChat asks the server to resend any missing packets. +In the past there have been issues where BYOND will silently and without reason lose a message we sent to the client, to detect this and recover from it seamlessly TgChat also has a baked in reliability layer. This reliability layer is very primitive, and simply keeps track of received sequence numbers. Should the client receive an unexpected sequence number TgChat asks the server to resend any missing packets. ### Ping System diff --git a/code/modules/tgs/README.md b/code/modules/tgs/README.md index 35ca73d7e9a..473442fd119 100644 --- a/code/modules/tgs/README.md +++ b/code/modules/tgs/README.md @@ -5,9 +5,9 @@ This folder should be placed on its own inside a codebase that wishes to use the - [includes.dm](./includes.dm) is the file that should be included by DM code, it handles including the rest. - The [core](./core) folder includes all code not directly part of any API version. - The other versioned folders contain code for the different DMAPI versions. - - [v3210](./v3210) contains the final TGS3 API. - - [v4](./v4) is the legacy DMAPI 4 (Used in TGS 4.0.X versions). - - [v5](./v5) is the current DMAPI version used by TGS >=4.1. + - [v3210](./v3210) contains the final TGS3 API. + - [v4](./v4) is the legacy DMAPI 4 (Used in TGS 4.0.X versions). + - [v5](./v5) is the current DMAPI version used by TGS >=4.1. - [LICENSE](./LICENSE) is the MIT license for the DMAPI. APIs communicate with TGS in two ways. All versions implement TGS -> DM communication using /world/Topic. DM -> TGS communication, called the bridge method, is different for each version. diff --git a/code/modules/tgs/core/README.md b/code/modules/tgs/core/README.md index 965e21b549a..7886a857149 100644 --- a/code/modules/tgs/core/README.md +++ b/code/modules/tgs/core/README.md @@ -2,7 +2,7 @@ This folder contains all DMAPI code not directly involved in an API. -- [_definitions.dm](./definitions.dm) contains defines needed across DMAPI internals. +- [\_definitions.dm](./definitions.dm) contains defines needed across DMAPI internals. - [byond_world_export.dm](./byond_world_export.dm) contains the default `/datum/tgs_http_handler` implementation which uses `world.Export()`. - [core.dm](./core.dm) contains the implementations of the `/world/proc/TgsXXX()` procs. Many map directly to the `/datum/tgs_api` functions. It also contains the /datum selection and setup code. - [datum.dm](./datum.dm) contains the `/datum/tgs_api` declarations that all APIs must implement. diff --git a/code/modules/tgs/v5/README.md b/code/modules/tgs/v5/README.md index a8a0c748e7b..fb374c2f872 100644 --- a/code/modules/tgs/v5/README.md +++ b/code/modules/tgs/v5/README.md @@ -2,8 +2,8 @@ This DMAPI implements bridge requests using HTTP GET requests to TGS. It has no security restrictions. -- [__interop_version.dm](./__interop_version.dm) contains the version of the API used between the DMAPI and TGS. -- [_defines.dm](./_defines.dm) contains constant definitions. +- [\_\_interop_version.dm](./__interop_version.dm) contains the version of the API used between the DMAPI and TGS. +- [\_defines.dm](./_defines.dm) contains constant definitions. - [api.dm](./api.dm) contains the bulk of the API code. - [bridge.dm](./bridge.dm) contains functions related to making bridge requests. - [chunking.dm](./chunking.dm) contains common function for splitting large raw data sets into chunks BYOND can natively process. diff --git a/code/modules/tickets/tickets.dm b/code/modules/tickets/tickets.dm index 3e44ca419af..1b44f6a5c3c 100644 --- a/code/modules/tickets/tickets.dm +++ b/code/modules/tickets/tickets.dm @@ -169,7 +169,7 @@ GLOBAL_DATUM_INIT(tickets, /datum/tickets, new) if(C.current_ticket) var/datum/ticket/T = C.current_ticket T.AddInteraction("Client disconnected.") - T.initiator.mob.clear_alert("open ticket") + T.initiator.mob?.clear_alert("open ticket") T.initiator = null T = null @@ -413,7 +413,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick/ticket_list) switch(level) if(0) for (var/client/C in GLOB.admins) - var/chat_msg = span_mentor_channel(span_admin_pm_notice(span_adminhelp("Ticket [TicketHref("#[id]", ref_src)]") + span_bold(" (Mentor): [LinkedReplyName(ref_src)] [FullMonty(ref_src, check_rights_for(C, (R_ADMIN|R_SERVER|R_MOD)))]:") + msg)) + var/chat_msg = span_mentor_channel(span_admin_pm_notice(span_adminhelp("Ticket [TicketHref("#[id]", ref_src)]") + span_bold(" (Mentor): [LinkedReplyName(ref_src)] [FullMonty(ref_src, check_rights_for(C, (R_ADMIN|R_SERVER|R_MOD)))]: ") + msg)) if (C.prefs?.read_preference(/datum/preference/toggle/play_mentorhelp_ping)) C << 'sound/effects/mentorhelp.mp3' to_chat(C, chat_msg) diff --git a/code/modules/tooltip/tooltip.html b/code/modules/tooltip/tooltip.html index ee355fa80e6..096a3c51f6b 100644 --- a/code/modules/tooltip/tooltip.html +++ b/code/modules/tooltip/tooltip.html @@ -1,269 +1,410 @@ -<!DOCTYPE html> +<!doctype html> <html> -<head> - <title>Tooltip - - - + + +
+
+
+ + - - + //Go get the map details + window.location = + "byond://winget?callback=tooltip.updateCallback;id=mapwindow.map;property=size,view-size"; + }, + }; + + diff --git a/config/docker/README.md b/config/docker/README.md index 3c1b9b34820..7e1fb0a0728 100644 --- a/config/docker/README.md +++ b/config/docker/README.md @@ -1,6 +1,5 @@ ## How to set-up the Docker database - First, open `config/docker/mysql.env.example`, open in notepad or N++, change all the values to something else ~~or don't if you are lazy~~ for security sake. Then proceed to save the changed version to `mysql.env` and save it in the same directory as the `mysql.env.example` file. diff --git a/config/example/jukebox.json b/config/example/jukebox.json index d2baa92532f..6863d7059ea 100644 --- a/config/example/jukebox.json +++ b/config/example/jukebox.json @@ -1,42 +1,42 @@ [ - { - "url": "https://s.put.re/bkZYkYwX.mp3", - "title": "Flip-Flap (Title One)", - "duration": 1500, - "artist": "X-CEED", - "secret": false, - "lobby": true, - "jukebox": false, - "genre": "Jazz" - }, - { - "url": "https://s.put.re/EzLP21Mp.mp3", - "title": "Robocop Theme (Title Two)", - "duration": 1180, - "artist": "Cboyardee", - "secret": false, - "lobby": true, - "jukebox": false, - "genre": "Electronic" - }, - { - "url": "https://s.put.re/uDpZrL1L.mp3", - "title": "Tin Tin on the Moon (Remix)", - "duration": 2320, - "artist": "Jeroen Tel (Remixed by Cuboos)", - "secret": false, - "lobby": true, - "jukebox": true, - "genre": "Electronic" - }, - { - "url": "https://s.put.re/nNXTd9ko.mp3", - "title": "Phoron Will Make Us Rich", - "duration": 1370, - "artist": "Earthcrusher", - "secret": false, - "lobby": true, - "jukebox": true, - "genre": "Electronic" - } -] \ No newline at end of file + { + "url": "https://s.put.re/bkZYkYwX.mp3", + "title": "Flip-Flap (Title One)", + "duration": 1500, + "artist": "X-CEED", + "secret": false, + "lobby": true, + "jukebox": false, + "genre": "Jazz" + }, + { + "url": "https://s.put.re/EzLP21Mp.mp3", + "title": "Robocop Theme (Title Two)", + "duration": 1180, + "artist": "Cboyardee", + "secret": false, + "lobby": true, + "jukebox": false, + "genre": "Electronic" + }, + { + "url": "https://s.put.re/uDpZrL1L.mp3", + "title": "Tin Tin on the Moon (Remix)", + "duration": 2320, + "artist": "Jeroen Tel (Remixed by Cuboos)", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://s.put.re/nNXTd9ko.mp3", + "title": "Phoron Will Make Us Rich", + "duration": 1370, + "artist": "Earthcrusher", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Electronic" + } +] diff --git a/config/example/jukebox_private.json b/config/example/jukebox_private.json index 0637a088a01..fe51488c706 100644 --- a/config/example/jukebox_private.json +++ b/config/example/jukebox_private.json @@ -1 +1 @@ -[] \ No newline at end of file +[] diff --git a/config/example/rules.html b/config/example/rules.html index d36a7bb415d..e4906e6c020 100644 --- a/config/example/rules.html +++ b/config/example/rules.html @@ -1,11 +1,11 @@ -Server Rules - - - - - - \ No newline at end of file + + diff --git a/config/example/webhooks.json b/config/example/webhooks.json index fc8ea883fbc..947e2c74f46 100644 --- a/config/example/webhooks.json +++ b/config/example/webhooks.json @@ -1,12 +1,12 @@ [ - { - "id" : "webhook_roundend", - "url" : { - "someurl0" : [], - "someurl1" : [], - "someurl2" : "somemention0", - "someurl3" : [ "somemention1", "somemention2" ] - }, - "mentions" : [ "somemention3", "somemention4" ] - } -] + { + "id": "webhook_roundend", + "url": { + "someurl0": [], + "someurl1": [], + "someurl2": "somemention0", + "someurl3": ["somemention1", "somemention2"] + }, + "mentions": ["somemention3", "somemention4"] + } +] diff --git a/config/jukebox.json b/config/jukebox.json index e3da041fafe..b6a956ffd32 100644 --- a/config/jukebox.json +++ b/config/jukebox.json @@ -1,4351 +1,4351 @@ [ -{ -"url": "https://files.catbox.moe/notc7y.mp3", -"title": "Flip-Flap (Title One)", -"duration": 1500, -"artist": "X-CEED", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/b24m07.mp3", -"title": "Robocop Theme (Title Two)", -"duration": 1180, -"artist": "Cboyardee", -"secret": false, -"lobby": true, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/qn5tdv.mp3", -"title": "Tin Tin on the Moon (Remix)", -"duration": 2450, -"artist": "Jeroen Tel (Remixed by Cuboos)", -"secret": false, -"lobby": true, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/uk3pr2.mp3", -"title": "Phoron Will Make Us Rich", -"duration": 1370, -"artist": "Earthcrusher", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/k25nxo.mp3", -"title": "Spaceman's Dilemma", -"duration": 2080, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/y1dxvn.mp3", -"title": "Banned from Argo", -"duration": 3150, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/zlct4c.mp3", -"title": "Stayin' Alive", -"duration": 2420, -"artist": "The Bee Gees", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/dluppg.m4a", -"title": "Tannhauser Overture", -"duration": 9360, -"artist": "Richard Wagner", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/b4j5jc.m4a", -"title": "Another Song About the Weekend", -"duration": 2250, -"artist": "A Day to Remember", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/n36iy9.m4a", -"title": "Truly Madly Deeply", -"duration": 2770, -"artist": "Savage Garden", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/t88x7z.m4a", -"title": "Adult Education", -"duration": 3230, -"artist": "Hall and Oates", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/k38d32.mp3", -"title": "That's All", -"duration": 2640, -"artist": "Genesis", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/b59gnc.mp3", -"title": "Faith", -"duration": 1580, -"artist": "George Michael", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/twy9ln.m4a", -"title": "Last Christmas", -"duration": 2630, -"artist": "Wham!", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/m00qlo.mp3", -"title": "Dreams", -"duration": 2920, -"artist": "Van Halen", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/fwvkr7.m4a", -"title": "Geronimo's Cadillac", -"duration": 1960, -"artist": "Modern Talking", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/py8x5m.m4a", -"title": "Home Sweet Home", -"duration": 2400, -"artist": "Motley Crue", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/ius137.mp3", -"title": "Too Young to Fall in Love", -"duration": 2100, -"artist": "Motley Crue", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/dc6s20.mp3", -"title": "Working for the Weekend", -"duration": 2220, -"artist": "Loverboy", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/977069.m4a", -"title": "Miles Away", -"duration": 2520, -"artist": "Winger", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/i5q08z.m4a", -"title": "Run, Sally, Run!", -"duration": 2870, -"artist": "Carpenter Brut", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/34kdfv.mp3", -"title": "Kickstart my Heart", -"duration": 2830, -"artist": "Motley Crue", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/ul3m8e.mp3", -"title": "Bizarre Love Triangle", -"duration": 2610, -"artist": "New Order", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/8f5h2b.mp3", -"title": "Regret", -"duration": 2490, -"artist": "New Order", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/8r1ifw.m4a", -"title": "Rule Britannia Overture", -"duration": 7320, -"artist": "Richard Wagner", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/75o3mo.m4a", -"title": "Da Ya Think I'm Sexy?", -"duration": 3270, -"artist": "Rod Stewart", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/s37xwb.m4a", -"title": "Missing You", -"duration": 2690, -"artist": "John Waite", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/nayw83.mp3", -"title": "Red Velvet", -"duration": 2080, -"artist": "NicolArmarfi", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/m8qpa4.m4a", -"title": "Space Age Love Song", -"duration": 2270, -"artist": "A Flock of Seagulls", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/shjfud.m4a", -"title": "Streets of Laredo", -"duration": 1690, -"artist": "Marty Robbins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/2qdzcj.m4a", -"title": "Crockett's Theme", -"duration": 2040, -"artist": "Jan Hammer", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/8ft96j.m4a", -"title": "Take Me Home", -"duration": 3510, -"artist": "Phil Collins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/q5c942.m4a", -"title": "Moonlight Sonata", -"duration": 8990, -"artist": "Ludwig van Beethoven", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/rlutyi.m4a", -"title": "We Built This City", -"duration": 2960, -"artist": "Starship", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/1rgsqr.m4a", -"title": "A Night on Bald Mountain", -"duration": 6830, -"artist": "Modest Mussorgsky", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/frq3un.m4a", -"title": "Keep on Loving You", -"duration": 2000, -"artist": "REO Speedwagon", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/z3v10u.m4a", -"title": "Lone Star", -"duration": 1470, -"artist": "Lost Weekend Western Swing Band", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/zg7gkh.m4a", -"title": "In The Shadow of the Valley", -"duration": 1870, -"artist": "Lost Weekend Western Swing Band", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/v4xtn8.m4a", -"title": "Blue Moon", -"duration": 1710, -"artist": "Frank Sinatra", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/w2ysbr.m4a", -"title": "I Will Wait", -"duration": 2760, -"artist": "Mumford and Sons", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/jim3bp.m4a", -"title": "You Can't Hurry Love", -"duration": 1760, -"artist": "Phil Collins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/r6jh89.m4a", -"title": "Big Iron", -"duration": 2350, -"artist": "Marty Robbins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/h698sa.m4a", -"title": "Overnight Sensation", -"duration": 2380, -"artist": "Firehouse", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/bmik55.mp3", -"title": "Lightnin' Strikes Again", -"duration": 2270, -"artist": "Dokken", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/0e0wmd.m4a", -"title": "Gettin' Jiggy Wit It", -"duration": 2270, -"artist": "Will Smith", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/fm20mk.m4a", -"title": "Lay It Down", -"duration": 2050, -"artist": "Ratt", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/xogao9.m4a", -"title": "Night Fever", -"duration": 2110, -"artist": "The Bee Gees", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/8gvr40.m4a", -"title": "Robot Rock", -"duration": 2870, -"artist": "Daft Punk", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/owzo1t.m4a", -"title": "Space Jam", -"duration": 3040, -"artist": "Quad City DJs", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/t4t9qi.m4a", -"title": "Take Me Home, Country Roads", -"duration": 1980, -"artist": "John Denver", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/il9tge.m4a", -"title": "White Collar Crime", -"duration": 4620, -"artist": "Simon Viklund", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/bcniut.m4a", -"title": "Carmen Miranda's Ghost", -"duration": 1340, -"artist": "Leslie Fish", -"secret": false, -"lobby": true, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/yg44gl.mp3", -"title": "Dawson's Christian", -"duration": 2660, -"artist": "Duane Elms", -"secret": false, -"lobby": true, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/fhvudh.m4a", -"title": "Good Ship Manatee", -"duration": 1700, -"artist": "Leslie Fish", -"secret": false, -"lobby": true, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/v5wm23.mp3", -"title": "Bomber", -"duration": 1920, -"artist": "Duane Elms", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/ych1i1.m4a", -"title": "Some Kind of Hero", -"duration": 4070, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/7rfftg.m4a", -"title": "Guardians", -"duration": 2370, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/yg7ndh.m4a", -"title": "One Last Battle", -"duration": 1580, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/8c3n30.m4a", -"title": "New Sins for Old", -"duration": 1520, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/t9i5vh.mp3", -"title": "Space Hero", -"duration": 1680, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/xbj8ep.mp3", -"title": "Sam Jones", -"duration": 5090, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/iiggpj.mp3", -"title": "Spacer's Home", -"duration": 2190, -"artist": "Duane Elms", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/1vowpl.m4a", -"title": "Harder, Better, Faster, Stronger", -"duration": 2260, -"artist": "Daft Punk", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/fnse07.m4a", -"title": "Crazy Train", -"duration": 2960, -"artist": "Ozzy Osbourne", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/z7b6ih.m4a", -"title": "Poison Arrow", -"duration": 2040, -"artist": "ABC", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/d874c4.m4a", -"title": "Everything Counts", -"duration": 2390, -"artist": "Depeche Mode", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/p9yfvg.m4a", -"title": "Legend Has It", -"duration": 2050, -"artist": "Run the Jewels", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/gg4pti.m4a", -"title": "Rasputin", -"duration": 2650, -"artist": "Boney M", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/u3ylxd.m4a", -"title": "Still D.R.E", -"duration": 2740, -"artist": "Dr. Dre (feat. Snoop Dogg)", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/2r3cbk.m4a", -"title": "It Was a Good Day", -"duration": 2600, -"artist": "Ice Cube", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/asthsu.m4a", -"title": "A Kiss to Build a Dream On", -"duration": 1840, -"artist": "Louis Armstrong", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/rze7qx.m4a", -"title": "(I Always Kill) The Things I Love", -"duration": 1750, -"artist": "The Real Tuesday Weld (feat. Claudia Brucken)", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/5o0uwa.mp3", -"title": "Invisible Touch", -"duration": 2080, -"artist": "Gensis", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/pdtbyi.m4a", -"title": "Tainted Love", -"duration": 1620, -"artist": "Soft Cell", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/j58vt2.mp3", -"title": "Everybody Wants To Rule The World", -"duration": 2520, -"artist": "Tears for Fears", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/llja8t.m4a", -"title": "Pink Cloud Days", -"duration": 1890, -"artist": "A.L.I.S.O.N", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/vbydgp.m4a", -"title": "Ethical Constraints Removed", -"duration": 2310, -"artist": "zircon & Jonathan Peros", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/y5tpk4.m4a", -"title": "The Blue Valley", -"duration": 7250, -"artist": "Karsten Koch", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/4vxedh.m4a", -"title": "Miami Disco", -"duration": 2700, -"artist": "Perturbator", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/dw5h51.m4a", -"title": "Shattered Dreams", -"duration": 2050, -"artist": "Johnny Hates Jazz", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/3zfcq0.mp3", -"title": "Miami", -"duration": 2730, -"artist": "Jasper Byrne", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/ecicu2.mp3", -"title": "Voyager", -"duration": 2140, -"artist": "Jasper Byrne", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/zfwxms.m4a", -"title": "Clouds of Fire", -"duration": 1170, -"artist": "Hector", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/5pl46n.m4a", -"title": "Every Day Is Night", -"duration": 2200, -"artist": "Garoad", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/0y4tjc.m4a", -"title": "Angel", -"duration": 3790, -"artist": "Massive Attack", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/ke8uk5.m4a", -"title": "Beware the Beast", -"duration": 2260, -"artist": "Carpenter Brut", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/u7yyft.m4a", -"title": "The Promise", -"duration": 2200, -"artist": "When In Rome", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/gcej08.m4a", -"title": "UNATCO - Conversation", -"duration": 1720, -"artist": "Michiel van den Bos", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/pf929m.m4a", -"title": "Virtual Insanity", -"duration": 3400, -"artist": "Jamiroquai", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/lu1gif.m4a", -"title": "Freek'n You", -"duration": 3790, -"artist": "Jodeci", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/g368sb.m4a", -"title": "And The Beat Goes On", -"duration": 4500, -"artist": "The Whispers", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/5ikte3.m4a", -"title": "Kiss From a Rose", -"duration": 2880, -"artist": "Seal", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/cqqyzj.m4a", -"title": "Sexual Healing", -"duration": 2430, -"artist": "Marvin Gaye", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/t9mwa9.m4a", -"title": "Sometimes", -"duration": 2530, -"artist": "Miami Horror", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/hdi0l9.m4a", -"title": "Nightcall", -"duration": 2580, -"artist": "Kavinsky", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/4pul1m.m4a", -"title": "Wash Away", -"duration": 2070, -"artist": "Alkaline Trio", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/whcm2r.m4a", -"title": "You Get What You Give", -"duration": 3000, -"artist": "New Radicals", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/adxl47.m4a", -"title": "Let's Dance", -"duration": 2500, -"artist": "David Bowie", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/50sksv.m4a", -"title": "Do It Again", -"duration": 3560, -"artist": "Steely Dan", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/j3ntvh.m4a", -"title": "Reelin' In The Years", -"duration": 2750, -"artist": "Steely Dan", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/utxphs.m4a", -"title": "Fire", -"duration": 1750, -"artist": "The Crazy World of Arthur Brown", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/5sh98r.m4a", -"title": "Everlong", -"duration": 2500, -"artist": "Foo Fighters", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/fdjdmj.m4a", -"title": "Limelight", -"duration": 2590, -"artist": "Rush", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/hdlhuf.m4a", -"title": "Revolution", -"duration": 2030, -"artist": "The Beatles", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/9hg3cr.m4a", -"title": "Dance the Night Away", -"duration": 1880, -"artist": "Van Halen", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/c961k1.m4a", -"title": "Blue Monday", -"duration": 4430, -"artist": "New Order", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/gldcwv.m4a", -"title": "Dancin' In the Ruins", -"duration": 2410, -"artist": "Blue Oyster Cult", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/1ckdtl.m4a", -"title": "The Boys Are Back In Town", -"duration": 2690, -"artist": "Thin Lizzy", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/w8plzv.m4a", -"title": "What It Takes", -"duration": 3110, -"artist": "Aerosmith", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/kdrv1r.m4a", -"title": "Angel", -"duration": 3080, -"artist": "Aerosmith", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/eh54mt.m4a", -"title": "Dude (Looks Like A Lady)", -"duration": 2650, -"artist": "Aerosmith", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/yczf2s.m4a", -"title": "Baba O'Riley", -"duration": 3000, -"artist": "The Who", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/v5376r.m4a", -"title": "Broken Wings", -"duration": 3430, -"artist": "Mr. Mister", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/r27dka.m4a", -"title": "Can't Fight This Feeling", -"duration": 2940, -"artist": "REO Speedwagon", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/a69sg1.m4a", -"title": "Talk Dirty To Me", -"duration": 2240, -"artist": "Poison", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/agtxnz.mp3", -"title": "Jump", -"duration": 2420, -"artist": "Van Halen", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/s8fzga.m4a", -"title": "Itz Nothin", -"duration": 2040, -"artist": "Young Roscoe", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/5qgnr9.m4a", -"title": "The Power Of Love", -"duration": 2340, -"artist": "Huey Lewis and The News", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/whbte8.m4a", -"title": "Just a Gigolo / I Ain't Got Nobody", -"duration": 2780, -"artist": "David Lee Roth", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/r32v4i.mp3", -"title": "True Faith", -"duration": 3540, -"artist": "New Order", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/oi7rov.m4a", -"title": "I Want You", -"duration": 2320, -"artist": "Savage Garden", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/tshasp.m4a", -"title": "Space Asshole", -"duration": 2340, -"artist": "Chris Remo", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/yfg6if.m4a", -"title": "Far Away", -"duration": 2810, -"artist": "Jose Gonzalez", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/6rbq2q.m4a", -"title": "All That Could Ever Be", -"duration": 3960, -"artist": "Rik Schaffer", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/l8baty.m4a", -"title": "Sleepwalking", -"duration": 2170, -"artist": "The Chain Gang of 1974", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/n6wwdu.m4a", -"title": "Take It On the Run", -"duration": 2390, -"artist": "REO Speedwagon", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/xwcipt.m4a", -"title": "Radio Ga Ga", -"duration": 3480, -"artist": "Queen", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/kq2ak3.m4a", -"title": "Dancing With Myself", -"duration": 2900, -"artist": "Billy Idol", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/ufk5gk.m4a", -"title": "Get Down Saturday Night", -"duration": 4100, -"artist": "Oliver Cheatham", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/3pvlwa.m4a", -"title": "Disco Inferno", -"duration": 2130, -"artist": "The Trammps", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/mt0w0u.mp3", -"title": "Wayfarer", -"duration": 2710, -"artist": "Kavinsky", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/wsjaml.m4a", -"title": "Papa Was A Rolling Stone", -"duration": 4180, -"artist": "The Temptations", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/ln6qoi.m4a", -"title": "I Don't Care Anymore", -"duration": 3050, -"artist": "Phil Collins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/sp6pks.m4a", -"title": "Throwing It All Away", -"duration": 2300, -"artist": "Genesis", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/1kv7kx.mp3", -"title": "In Too Deep", -"duration": 2980, -"artist": "Genesis", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/u42u20.mp3", -"title": "Easy Lover", -"duration": 3020, -"artist": "Phil Collins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/vwlu1a.mp3", -"title": "How To Be A Millionaire", -"duration": 2150, -"artist": "ABC", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/r6d520.mp3", -"title": "Hip To Be Square", -"duration": 2450, -"artist": "Huey Lewis and The News", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/i7qhge.m4a", -"title": "You've Got Another Thing Coming", -"duration": 3100, -"artist": "Judas Priest", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/16y3iy.m4a", -"title": "Live Wire", -"duration": 1940, -"artist": "Motley Crue", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/4sdesv.m4a", -"title": "Ace of Spades", -"duration": 1670, -"artist": "Motorhead", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/3qqt2v.m4a", -"title": "Rise Of The Chaos Wizards", -"duration": 2370, -"artist": "Gloryhammer", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/fgcdu2.m4a", -"title": "Turn Up the Radio", -"duration": 2780, -"artist": "Autograph", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/86ylwc.mp3", -"title": "Bark at the Moon", -"duration": 2560, -"artist": "Ozzy Osbourne", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/nfxzcn.m4a", -"title": "Cum on Feel the Noize", -"duration": 2900, -"artist": "Quiet Riot", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/gl22vl.m4a", -"title": "The Hellion / Electric Eye", -"duration": 2610, -"artist": "Judas Priest", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/j4fvlc.mp3", -"title": "2 Minutes To Midnight", -"duration": 3600, -"artist": "Iron Maiden", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/sj1o0z.m4a", -"title": "Restless Gypsy", -"duration": 2990, -"artist": "W.A.S.P", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/lkkq00.m4a", -"title": "Universe On Fire", -"duration": 2460, -"artist": "Gloryhammer", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/ftmgxf.m4a", -"title": "Girls, Girls, Girls", -"duration": 2700, -"artist": "Motley Crue", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/uciolb.m4a", -"title": "To Hell with the Devil", -"duration": 2440, -"artist": "Stryper", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/6x9zur.m4a", -"title": "God Blessed Video", -"duration": 2100, -"artist": "Alcatrazz", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/gmgh6w.m4a", -"title": "Cumin' Atcha Live", -"duration": 2660, -"artist": "Tesla", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/zti66s.m4a", -"title": "Heavy Metal: The Black and Silver", -"duration": 2000, -"artist": "Blue Oyster Cult", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/8ew21k.m4a", -"title": "Mars For The Rich", -"duration": 2510, -"artist": "King Gizzard & the Lizard Wizard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/di9apc.m4a", -"title": "Insane in the Membrane", -"duration": 2100, -"artist": "Cypress Hill", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/8nyu9s.m4a", -"title": "Just a Friend", -"duration": 2380, -"artist": "Biz Markie", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/2b0wu2.m4a", -"title": "Intergalactic", -"duration": 2290, -"artist": "Beastie Boys", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/nv66ck.mp3", -"title": "Wild Child", -"duration": 3120, -"artist": "W.A.S.P", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/z3k8rs.m4a", -"title": "Icarus' Dream Suite Op.4", -"duration": 5140, -"artist": "Yngwie Malmsteen", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/57ghcq.m4a", -"title": "Fantasy", -"duration": 3030, -"artist": "Aldo Nova", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/kwwvsg.m4a", -"title": "Nocturne Op.9 No.2", -"duration": 2690, -"artist": "Frederic Chopin", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/zab3he.mp3", -"title": "Concord", -"duration": 1850, -"artist": "NicolArmarfi & Blue123", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/e52gys.mp3", -"title": "Clair de Lune", -"duration": 3570, -"artist": "Claude Debussy", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/e7nk9a.mp3", -"title": "Gymnopedie No.1", -"duration": 1870, -"artist": "Erik Satie", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/wf7jr8.mp3", -"title": "Johans Waltz", -"duration": 2860, -"artist": "Andreas Waldetoft", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/15ybh9.mp3", -"title": "Handel This", -"duration": 890, -"artist": "Andreas Waldetoft", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/0294ze.m4a", -"title": "Lohengrin: Prelude", -"duration": 5930, -"artist": "Richard Wagner", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/xgq1tr.m4a", -"title": "Concerto Grosso no. 10 in B Minor - Allegro", -"duration": 2150, -"artist": "Antonio Vivaldi", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/vxe2qt.m4a", -"title": "Ancient Stones", -"duration": 2850, -"artist": "Jeremy Soule", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/8bdxq3.m4a", -"title": "Secunda", -"duration": 1230, -"artist": "Jeremy Soule", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/lqgoiv.m4a", -"title": "Far Horizons", -"duration": 3310, -"artist": "Jeremy Soule", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/azzap9.mp3", -"title": "Time of Change", -"duration": 2020, -"artist": "FlybyNo", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/m67gzk.m4a", -"title": "Dreamer's Rest", -"duration": 2380, -"artist": "Vindsvept", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/tnx2fb.mp3", -"title": "Moment of Decision", -"duration": 2430, -"artist": "NicolArmarfi", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Classical and Orchestral" -}, -{ -"url": "https://files.catbox.moe/c7yeau.mp3", -"title": "In My Dreams", -"duration": 2600, -"artist": "Dokken", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/u8xh6b.m4a", -"title": "Wasted Years", -"duration": 3090, -"artist": "Iron Maiden", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/utjagr.m4a", -"title": "Round and Round", -"duration": 2650, -"artist": "Ratt", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/mbzbla.m4a", -"title": "Crystal Ball", -"duration": 2950, -"artist": "Yngwie Malmsteen", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/p9cnth.m4a", -"title": "I Remember You", -"duration": 3130, -"artist": "Skid Row", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/pkhotw.m4a", -"title": "I Won't Forget You", -"duration": 2150, -"artist": "Poison", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/231ksl.m4a", -"title": "Pjanoo (Club Mix)", -"duration": 4500, -"artist": "Eric Prydz", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/58hrry.m4a", -"title": "Inferno Galore", -"duration": 2250, -"artist": "Carpenter Brut", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/vsdg7v.m4a", -"title": "Low Rider", -"duration": 1910, -"artist": "War", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/gu2yfz.m4a", -"title": "How Deep Is Your Love", -"duration": 2450, -"artist": "The Bee Gees", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/slm18k.m4a", -"title": "You Dropped A Bomb On Me", -"duration": 3120, -"artist": "The Gap Band", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/24cqmw.m4a", -"title": "Every Rose Has It's Thorn", -"duration": 2600, -"artist": "Poison", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/v3otpl.m4a", -"title": "Fallen Angel", -"duration": 2380, -"artist": "Poison", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/iezn71.m4a", -"title": "Baby Hold On", -"duration": 2100, -"artist": "Eddie Money", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/e8w3ym.m4a", -"title": "Two Tickets To Paradise", -"duration": 2370, -"artist": "Eddie Money", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/cavpff.m4a", -"title": "Take Me Home Tonight", -"duration": 2110, -"artist": "Eddie Money", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/n8l93a.m4a", -"title": "Same Ol' Situation (S.O.S.)", -"duration": 2530, -"artist": "Motely Crue", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/gnr6py.m4a", -"title": "Metal Health (Bang Your Head)", -"duration": 3160, -"artist": "Quiet Riot", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/1drakx.m4a", -"title": "Shout At The Devil", -"duration": 1950, -"artist": "Motley Crue", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/1kevft.m4a", -"title": "Walk With Me in Hell", -"duration": 3110, -"artist": "Lamb of God", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/9cdsmd.m4a", -"title": "Crazy (A Suitable Case For Treatment)", -"duration": 2070, -"artist": "Nazareth", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/6oq1qw.m4a", -"title": "Freezing Moon", -"duration": 3830, -"artist": "Mayhem", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/jrc74a.m4a", -"title": "Raining Blood", -"duration": 2540, -"artist": "Slayer", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/ey07dt.m4a", -"title": "Marching Off to War", -"duration": 2490, -"artist": "Motorhead", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/a77r2l.m4a", -"title": "Hymn Of The Forsaken", -"duration": 3880, -"artist": "Climmhazard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/omm3y6.m4a", -"title": "Victory Song", -"duration": 6390, -"artist": "Ensiferum", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/sx7kbr.m4a", -"title": "Dunkelheit", -"duration": 4210, -"artist": "Burzum", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/r6uftn.m4a", -"title": "Sick Bubblegum", -"duration": 2240, -"artist": "Rob Zombie", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/ysee6q.m4a", -"title": "Laser Enforcer", -"duration": 2540, -"artist": "Slough Feg", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/sxcus4.m4a", -"title": "Veteran of the Psychic Wars", -"duration": 2890, -"artist": "Blue Oyster Cult", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/qkxavx.m4a", -"title": "Tiger! Tiger!", -"duration": 2530, -"artist": "Slough Feg", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/u7rhxc.m4a", -"title": "Hyperdrive", -"duration": 2140, -"artist": "The Devin Townsend Project", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/narev2.m4a", -"title": "Judas", -"duration": 2500, -"artist": "Fozzy", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/pguvz2.m4a", -"title": "Alone Again", -"duration": 2600, -"artist": "Dokken", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/0gol3u.m4a", -"title": "Superbeast", -"duration": 2200, -"artist": "Rob Zombie", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/irrxal.m4a", -"title": "Perihelion", -"duration": 1910, -"artist": "King Gizzard & The Lizard Wizard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/f9yw8d.m4a", -"title": "Self-Immolate", -"duration": 2680, -"artist": "King Gizzard & The Lizard Wizard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/zmyym2.m4a", -"title": "Planet B", -"duration": 2360, -"artist": "King Gizzard & The Lizard Wizard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/isa0lb.m4a", -"title": "On The Wind", -"duration": 2250, -"artist": "Dream Evil", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/oi9dt1.m4a", -"title": "Catch The Rainbow", -"duration": 3960, -"artist": "Rainbow", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/1ozes3.m4a", -"title": "Peace Sells", -"duration": 2440, -"artist": "Megadeth", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Metal" -}, -{ -"url": "https://files.catbox.moe/iyi2ll.m4a", -"title": "Never Gonna Give You Up", -"duration": 2130, -"artist": "Rick Astley", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/s46vw9.m4a", -"title": "I Fought The Law", -"duration": 1630, -"artist": "The Clash", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/3blefo.m4a", -"title": "Piano Man", -"duration": 3400, -"artist": "Billy Joel", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/qq4cbx.m4a", -"title": "Mr. Blue Sky", -"duration": 3030, -"artist": "Electric Light Orchestra", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/uxwl09.m4a", -"title": "Here I Go Again (1987 Version)", -"duration": 2750, -"artist": "Whitesnake", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/jgigel.m4a", -"title": "Starman", -"duration": 2540, -"artist": "David Bowie", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/nq2w6w.m4a", -"title": "Space Oddity", -"duration": 3180, -"artist": "David Bowie", -"secret": false, -"lobby": true, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/2n2gdq.m4a", -"title": "Changes", -"duration": 2170, -"artist": "David Bowie", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/jzucsv.mp3", -"title": "A Horse With No Name", -"duration": 2470, -"artist": "America", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/d05y2k.m4a", -"title": "Space Oddity (Cover)", -"duration": 3330, -"artist": "Chris Hadfield", -"secret": false, -"lobby": true, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/1gbbu1.m4a", -"title": "Cruel, Cruel World (Josh Homme)", -"duration": 2140, -"artist": "Josh Homme", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/3941ms.m4a", -"title": "House Building", -"duration": 2200, -"artist": "David 'Fergie' Ferguson", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/rf6v2o.m4a", -"title": "Folsom Prison Blues", -"duration": 1680, -"artist": "Johnny Cash", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/1deyd1.m4a", -"title": "A White Sport Coat (And a Pink Carnation)", -"duration": 1480, -"artist": "Marty Robbins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/r7asbn.m4a", -"title": "Lovers Of The World", -"duration": 1680, -"artist": "Jerry Wallace", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/gdd5v3.m4a", -"title": "Cruel, Cruel World (Willie Nelson)", -"duration": 2660, -"artist": "Willie Nelson", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/vrj0cl.m4a", -"title": "The Story Of A Soldier", -"duration": 2390, -"artist": "Ennio Morricone", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/wdswuf.m4a", -"title": "Rawhide", -"duration": 1200, -"artist": "Frankie Laine", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/sa9lg3.m4a", -"title": "Psycho", -"duration": 2160, -"artist": "Eddie Noack", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/j84ln2.m4a", -"title": "Before You Use That Gun", -"duration": 1520, -"artist": "Eddie Noack", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/3ae5p2.m4a", -"title": "Rhinestone Cowboy", -"duration": 2090, -"artist": "Glen Campbell", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/hbc1vd.m4a", -"title": "Flowers on the Wall", -"duration": 1390, -"artist": "The Statler Brothers", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/7ibtm1.m4a", -"title": "Bed Of Roses", -"duration": 1480, -"artist": "The Statler Brothers", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/mv8xql.m4a", -"title": "New York City", -"duration": 1710, -"artist": "The Statler Brothers", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/5mtinr.m4a", -"title": "The Devil Went Down to Georgia", -"duration": 2140, -"artist": "The Charlie Daniels Band", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/qvd0qg.m4a", -"title": "Cottonwood Tree", -"duration": 2370, -"artist": "Marty Robbins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/378qb4.m4a", -"title": "Ain't I Right", -"duration": 1980, -"artist": "Marty Robbins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/5sgpkn.m4a", -"title": "Wish It Was True", -"duration": 2280, -"artist": "The White Buffalo", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/de3b29.m4a", -"title": "Burn The Witch", -"duration": 2480, -"artist": "Shawn James", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/av3j0o.m4a", -"title": "Sink The Bismarck", -"duration": 1940, -"artist": "Johnny Horton", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/8z0ueu.m4a", -"title": "Mr. Shorty", -"duration": 3030, -"artist": "Marty Robbins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/0wwk0d.m4a", -"title": "Uneasy Rider", -"duration": 3180, -"artist": "The Charlie Daniels Band", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/dws0dz.m4a", -"title": "Uneasy Rider '88", -"duration": 2640, -"artist": "The Charlie Daniels Band", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/ci1gka.m4a", -"title": "For A Few Dollars More", -"duration": 1680, -"artist": "Ennio Morricone", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Country and Western" -}, -{ -"url": "https://files.catbox.moe/pbw43i.m4a", -"title": "Faster Than Light", -"duration": 2370, -"artist": "Ben Prunty", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/va5a54.m4a", -"title": "Rebecca", -"duration": 2540, -"artist": "Tesla Boy", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/g3mwvn.m4a", -"title": "Zero Point Non-Response", -"duration": 3330, -"artist": "Mega Drive", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/fu3mf9.m4a", -"title": "Edge of Reality", -"duration": 3300, -"artist": "Mega Drive", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/nspw3i.m4a", -"title": "What Is Love", -"duration": 2700, -"artist": "Haddaway", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/8kyy4o.mp3", -"title": "Time Lapse", -"duration": 2600, -"artist": "Kalax", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/yuwdr5.m4a", -"title": "So Far Away", -"duration": 2820, -"artist": "Lazerhawk", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/hlsk69.m4a", -"title": "Children of the Omnissiah", -"duration": 1060, -"artist": "Guillaume David", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/t7q36u.m4a", -"title": "Noosphere", -"duration": 3880, -"artist": "Guillaume David", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/e2lxd4.m4a", -"title": "Resonance", -"duration": 2120, -"artist": "HOME", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/fnngli.m4a", -"title": "We're Finally Landing", -"duration": 2720, -"artist": "HOME", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/36juno.mp3", -"title": "Head First", -"duration": 2130, -"artist": "HOME", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/bvwhm0.m4a", -"title": "Dust", -"duration": 3020, -"artist": "M|O|O|N", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/b6urx6.m4a", -"title": "Silent Strike", -"duration": 2970, -"artist": "Garth Knight", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/ywr4gd.mp3", -"title": "Night Train", -"duration": 2440, -"artist": "Mitch Murder", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/rgtjn3.m4a", -"title": "Welcome to VA-11 Hall-A", -"duration": 1880, -"artist": "Garoad", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/86wwz1.m4a", -"title": "Drive Me Wild", -"duration": 2280, -"artist": "Garoad", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/j14cpw.m4a", -"title": "Sexualizer", -"duration": 2990, -"artist": "Perturbator (feat. Flash Arnold)", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/3zb1hx.m4a", -"title": "Into The Labyrinth", -"duration": 3100, -"artist": "Kraddy", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/qxadpn.m4a", -"title": "Turbo Killer", -"duration": 2080, -"artist": "Carpenter Brut", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/dclq52.m4a", -"title": "Deep Cover", -"duration": 4850, -"artist": "Sun Araw", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/wpws58.m4a", -"title": "Fragments of Bach I", -"duration": 3060, -"artist": "Compilerbau", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/ltlzpi.mp3", -"title": "Leather Teeth", -"duration": 2330, -"artist": "Carpenter Brut", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/bem2ur.m4a", -"title": "Cheerleader Effect", -"duration": 2170, -"artist": "Carpenter Brut", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/hwfg7e.m4a", -"title": "Hairspray Hurricane", -"duration": 3310, -"artist": "Carpenter Brut", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/xx00ka.m4a", -"title": "Sunday Lunch", -"duration": 1950, -"artist": "Carpenter Brut", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/4ju4p1.mp3", -"title": "Lone Digger", -"duration": 2300, -"artist": "Caravan Palace", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/4c0lmk.m4a", -"title": "Dessert", -"duration": 1840, -"artist": "Jun Chikuma", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/g0ms06.m4a", -"title": "Propane Nightmares", -"duration": 3130, -"artist": "Pendulum", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/7i23kv.m4a", -"title": "Overdrive (Instrumental)", -"duration": 2260, -"artist": "Lily Arciniega", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/re4is1.m4a", -"title": "Tusk", -"duration": 2180, -"artist": "Fleetwood Mac", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/xztay0.m4a", -"title": "Rock On Rockall", -"duration": 1740, -"artist": "The Wolfe Tones", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/6ryyk0.m4a", -"title": "Apocalypse", -"duration": 2900, -"artist": "Cigarettes After Sex", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/2z6lpx.mp3", -"title": "Pioneer's Song", -"duration": 1790, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/e55ey0.mp3", -"title": "Bones", -"duration": 1200, -"artist": "Leslie Fish", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Folk and Indie" -}, -{ -"url": "https://files.catbox.moe/evilyr.m4a", -"title": "Age of Consent", -"duration": 3150, -"artist": "New Order", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/lgot68.m4a", -"title": "Maneater", -"duration": 2730, -"artist": "Hall & Oates", -"secret": false, -"lobby": true, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/8e4bb0.m4a", -"title": "Ordinary World", -"duration": 3400, -"artist": "Duran Duran", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/leulle.m4a", -"title": "Forever Young", -"duration": 2260, -"artist": "Alphaville", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/z8bxjp.m4a", -"title": "Sussudio", -"duration": 2640, -"artist": "Phil Collins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/wti40y.m4a", -"title": "One More Night", -"duration": 2910, -"artist": "Phil Collins", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/zifzgk.m4a", -"title": "Little Girls", -"duration": 2230, -"artist": "Oingo Boingo", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/5yk0mm.m4a", -"title": "Everything She Wants", -"duration": 3920, -"artist": "Wham!", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/5ye8et.m4a", -"title": "Careless Whisper", -"duration": 3030, -"artist": "George Michael", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/9a5dov.m4a", -"title": "Space Cowboy", -"duration": 2160, -"artist": "Jamiroquai", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Disco, Funk, Soul, and R&B" -}, -{ -"url": "https://files.catbox.moe/dpjb9r.m4a", -"title": "Video Killed The Radio Star", -"duration": 2530, -"artist": "The Buggles", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/367b33.m4a", -"title": "Honey, There's No Time", -"duration": 2610, -"artist": "Feng Suave", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/q5kk5l.m4a", -"title": "Sink into the Floor", -"duration": 2790, -"artist": "Feng Suave", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/w7d9qk.m4a", -"title": "This Train", -"duration": 2850, -"artist": "Turk Murphy's San Francisco Jazz Band", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/79d8gs.mp3", -"title": "Love Theme", -"duration": 5710, -"artist": "Andrew Hale", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/u1h4vg.m4a", -"title": "Jingle Jangle Jingle", -"duration": 1970, -"artist": "Kay Kyser", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/ky7dvn.m4a", -"title": "Personality", -"duration": 1690, -"artist": "Johnny Mercer & The Pied Pipers", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/5jm318.m4a", -"title": "Let's Face The Music And Dance", -"duration": 1710, -"artist": "Frank Sinatra", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/jhjidm.m4a", -"title": "I'll Get By", -"duration": 1700, -"artist": "Frank Fontaine", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/bwg49y.m4a", -"title": "That Face!", -"duration": 1430, -"artist": "Frank Sinatra Jr", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/2wmc3x.m4a", -"title": "Mack the Knife", -"duration": 1840, -"artist": "Bobby Darin", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/q2t0i0.m4a", -"title": "The Day The Clown Cried", -"duration": 1900, -"artist": "Jimmy Beaumont & The Skyliners", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/c06zik.m4a", -"title": "Invitation To The Blues", -"duration": 3240, -"artist": "Tom Waits", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/1z0mli.m4a", -"title": "Drunk On The Moon", -"duration": 3060, -"artist": "Tom Waits", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/dqu0t5.m4a", -"title": "La Vie En Rose", -"duration": 2050, -"artist": "Louis Armstrong", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/0ys4q8.m4a", -"title": "So What", -"duration": 5690, -"artist": "Miles Davis Sextet", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/nr7btw.m4a", -"title": "Just The Two Of Us", -"duration": 4430, -"artist": "Grover Washington Jr", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/tb9ys2.m4a", -"title": "Quiet Nights Of Quiet Stars", -"duration": 1640, -"artist": "Frank Sinatra & Antonio Carlos Jobim", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/zd1sw1.m4a", -"title": "Drinking Water", -"duration": 1530, -"artist": "Frank Sinatra & Antonio Carlos Jobim", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/fwtdoh.m4a", -"title": "Ol' Man River (Showboat)", -"duration": 2340, -"artist": "Paul Robseon", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Jazz" -}, -{ -"url": "https://files.catbox.moe/mp8tab.m4a", -"title": "Juke Box Hero", -"duration": 2590, -"artist": "Foreigner", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/n0ezuw.m4a", -"title": "Waiting for a Girl Like You", -"duration": 2890, -"artist": "Foreigner", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/gd49uk.m4a", -"title": "I Want to Know What Love Is", -"duration": 3040, -"artist": "Foreigner", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/s36f97.m4a", -"title": "She Sells Sanctuary", -"duration": 2620, -"artist": "The Cult", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/62lks9.m4a", -"title": "No One Knows", -"duration": 2580, -"artist": "Queens of the Stone Age", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/e4sltu.m4a", -"title": "Like a Stone", -"duration": 2940, -"artist": "Audioslave", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/yitsz9.m4a", -"title": "Friday I'm in Love", -"duration": 2140, -"artist": "The Cure", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Pop" -}, -{ -"url": "https://files.catbox.moe/dwyjkt.m4a", -"title": "Ozymandias", -"duration": 1920, -"artist": "Red Vox", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/wmpgcr.mp3", -"title": "Welcome To The Jungle", -"duration": 2690, -"artist": "Guns N' Roses", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/20exnb.mp3", -"title": "Fortunate Son", -"duration": 1400, -"artist": "Creedence Clearwater Revival", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/8xzmw5.mp3", -"title": "Bohemian Rhapsody", -"duration": 3580, -"artist": "Queen", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/7x2cvf.mp3", -"title": "Rocket Man", -"duration": 2820, -"artist": "Elton John", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/xjgch6.m4a", -"title": "Smooth Sailing", -"duration": 2910, -"artist": "Queens of the Stone Age", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/f8ebif.m4a", -"title": "Face Melter (How to Do Impossible Things)", -"duration": 2100, -"artist": "Death Grips", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/6i31kh.m4a", -"title": "Rapper's Delight", -"duration": 8850, -"artist": "The Sugar Hill Gang", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/3y9k43.m4a", -"title": "Super Freak", -"duration": 2020, -"artist": "Rick James", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/93ynna.m4a", -"title": "Party All The Time", -"duration": 2530, -"artist": "Eddie Murphy", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/4s8xyr.m4a", -"title": "Funky Cold Medina", -"duration": 2480, -"artist": "Tone-Loc", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/jzpkv4.m4a", -"title": "Children's Story", -"duration": 2420, -"artist": "Slick Rick", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/tk1zno.m4a", -"title": "Voila", -"duration": 2080, -"artist": "Death Grips", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/jvhl18.m4a", -"title": "Black Ballons Reprise", -"duration": 1620, -"artist": "Flying Lotus (feat. Denzel Curry)", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/59nnfc.m4a", -"title": "Take_it_Back_v2", -"duration": 1690, -"artist": "Denzel Curry & Kenny Beats", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/pkwkd1.m4a", -"title": "All Caps", -"duration": 1340, -"artist": "Madvillain", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/d7zx95.m4a", -"title": "Express Yourself", -"duration": 2650, -"artist": "N.W.A", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/fgn4pf.m4a", -"title": "BLACK BALLOONS", -"duration": 2100, -"artist": "Denzel Curry", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/o7hb3j.m4a", -"title": "Meat Grinder", -"duration": 1310, -"artist": "Madvillain", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Hip-Hop and Rap" -}, -{ -"url": "https://files.catbox.moe/8o0z0l.m4a", -"title": "Keep Your Eyes Peeled", -"duration": 3040, -"artist": "Queens of the Stone Age", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/ri8l16.m4a", -"title": "Sleep Drifter", -"duration": 2840, -"artist": "King Gizzard & The Lizard Wizard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/zz1p3n.m4a", -"title": "Open Water", -"duration": 4330, -"artist": "King Gizzard & The Lizard Wizard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/prllpr.m4a", -"title": "Gamma Knife", -"duration": 2910, -"artist": "King Gizzard & The Lizard Wizard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/v66qvy.m4a", -"title": "Baby Gotterdammerung", -"duration": 1880, -"artist": "Monster Magnet", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/isus1b.m4a", -"title": "Robot Stop", -"duration": 2100, -"artist": "King Gizzard & The Lizard Wizard", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/qhionp.mp3", -"title": "Come Sail Away", -"duration": 3650, -"artist": "Styx", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/vm93di.m4a", -"title": "Bullet Girl", -"duration": 3210, -"artist": "John Butler Trio", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/f3gvmk.m4a", -"title": "Holland, 1945", -"duration": 1920, -"artist": "Neutral Milk Hotel", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Rock" -}, -{ -"url": "https://files.catbox.moe/8rn8uz.mp3", -"title": "I Wupped Batman's Ass", -"duration": 3270, -"genre": "Miscellaneous", -"artist": "Wesley Willis Fiasco", -"secret": true, -"lobby": false, -"jukebox": true -}, -{ -"url" : "https://files.catbox.moe/h967s5.mp3", -"title" : "MEGALOVANIA", -"duration" : 1416, -"artist" : "Toby Fox", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Video Game" -}, -{ -"url" : "https://files.catbox.moe/yumfgs.mp3", -"title" : "ASGORE", -"duration" : 1416, -"artist" : "Toby Fox", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Video Game" -}, -{ -"url" : "https://files.catbox.moe/ewn2u4.mp3", -"title" : "Disco Descent", -"duration" : 1800, -"artist" : "Danny Baranowsky", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url" : "https://files.catbox.moe/8rns1d.mp3", -"title" : "Konga Conga Kappa", -"duration" : 1130, -"artist" : "Danny Baranowsky", -"secret": false, -"lobby": false, -"jukebox": true, -"genre": "Electronic" -}, -{ -"url": "https://files.catbox.moe/3h38kn.mp3", -"title": "Among Us", -"duration": 720, -"artist": "Leonz", -"genre": "Disco, Funk, Soul, and R&B", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/rqhxj1.mp3", -"title": "Leggy Zone", -"duration": 1470, -"artist": "Binox", -"genre": "Electronic", -"secret": true, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/e6l6mw.mp3", -"title": "Shop Theme", -"duration": 8910, -"artist": "Kazumi Totaka/Nintendo", -"genre": "Electronic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/q2ob3n.mp3", -"title": "PONPONPON", -"duration": 2430, -"artist": "Kyary Pamyu Pamyu", -"genre": "J-Pop", -"secret": false, -"lobby": false -}, -{ -"url": "https://files.catbox.moe/o8flhu.mp3", -"title": "Man's Road", -"duration": 2060, -"artist": "America", -"genre": "Rock", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/0gb5qs.mp3", -"title": "Passionflower", -"duration": 3840, -"artist": "Jon Gomm", -"genre": "Rock", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/p5e28z.mp3", -"title": "What the Fuck", -"duration": 2420, -"artist": "Koh", -"genre": "Folk and Indie", -"secret": true, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/0f2xma.mp3", -"title": "Bonetrousle", -"duration": 580, -"artist": "Toby Fox", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/6ivc7w.mp3", -"title": "Bury the Light", -"duration": 5830, -"artist": "Victor Borba & Casey Edwards", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/pbtbjv.mp3", -"title": "Dog Song", -"duration": 380, -"artist": "Toby Fox", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/4v3eeb.mp3", -"title": "Anticipation", -"duration": 230, -"artist": "Toby Fox", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/0q8ch6.mp3", -"title": "Smash Clown", -"duration": 820, -"artist": "Goat", -"genre": "Space", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/ygcg2e.mp3", -"title": "Honk The Police", -"duration": 590, -"artist": "Goat", -"genre": "Space", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/h0yswi.mp3", -"title": "Cargonia", -"duration": 630, -"artist": "Goat", -"genre": "Space", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/xg76ja.mp3", -"title": "Hail Cargonia", -"duration": 980, -"artist": "Goat", -"genre": "Space", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/tbr2rc.mp3", -"title": "Banned From Cargo", -"duration": 2450, -"artist": "Goat", -"genre": "Space", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/tw2et2.mp3", -"title": "Periphery Dixie", -"duration": 1200, -"artist": "Goat", -"genre": "Space", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/rm5hcs.mp3", -"title": "Cargonia (cover)", -"duration": 2730, -"artist": "Dadbot5000", -"genre": "Space", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/ybfof9.mp3", -"title": "The Legend", -"duration": 1120, -"artist": "Toby Fox", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/ugfx06.mp3", -"title": "Field of Hopes and Dreams", -"duration": 1610, -"artist": "Toby Fox", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/wr08om.mp3", -"title": "Checker Dance", -"duration": 780, -"artist": "Toby Fox", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/4au954.mp3", -"title": "Vs Susie", -"duration": 810, -"artist": "Toby Fox", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/c9y5x2.mp3", -"title": "Golden Wind", -"duration": 2930, -"artist": "Yugo Kanno", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/ymvtem.mp3", -"title": "Sono Chi no Sadame", -"duration": 2610, -"artist": "Hiroaki TOMMY Tominaga", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/z73u05.mp3", -"title": "Bloody Stream", -"duration": 2590, -"artist": "Coda", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/yg3643.mp3", -"title": "Stand Proud", -"duration": 2750, -"artist": "Jin Hashimoto", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/344qrf.mp3", -"title": "Sono Chi no Kioku ~end of THE WORLD~", -"duration": 2620, -"artist": "JO☆STARS", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/0n6y6v.mp3", -"title": "Crazy Noisy Bizarre Town", -"duration": 1840, -"artist": "THE DU", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/j3xzw6.mp3", -"title": "Chase", -"duration": 1450, -"artist": "Batta", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/luf1bh.mp3", -"title": "Great Days", -"duration": 2400, -"artist": "Karen Aoki & Daisuke Hasegaw", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/ytp4d2.mp3", -"title": "Fighting Gold", -"duration": 2540, -"artist": "Coda", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/q1xjdp.mp3", -"title": "I Want It That Way", -"duration": 2120, -"artist": "Backstreet Boys", -"genre": "Pop", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/pxpkat.mp3", -"title": "Shop Theme Cover", -"duration": 1770, -"artist": "Songe", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/nz03o1.mp3", -"title": "Deep Space 9 (Cover)", -"duration": 1220, -"artist": "Heropoint", -"genre": "Rock", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/n4vcnq.mp3", -"title": "Trouble Shooting Star", -"duration": 1460, -"artist": "", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/byy378.mp3", -"title": "The Lord of the Rings The Fellowship of the its my book they will walk if I tell them to", -"duration": 970, -"artist": "Tom Cardy", -"genre": "Folk and Indie", -"secret": true, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/akgbup.mp3", -"title": "Flight of the Bumblebee", -"duration": 2050, -"artist": "Rimsky Korsakov", -"genre": "Classical and Orchestral", -"secret": true, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/milk8o.mp3", -"title": "As Heaven Is Wide", -"duration": 2880, -"artist": "Garbage", -"genre": "Rock", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/8mh82l.mp3", -"title": "Combat Montage", -"duration": 1410, -"artist": "Kevin Manthei", -"genre": "Rock", -"secret": true, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/qa6ahi.mp3", -"title": "Deadlines", -"duration": 1570, -"artist": "Network Music Ensemble", -"genre": "Rock", -"secret": false, -"lobby": true, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/cdmm5k.mp3", -"title": "Holding Out For A Hero", -"duration": 2620, -"artist": "Ella Mae Bowen", -"genre": "Country and Western", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/jlv9eb.mp3", -"title": "Jiko Bunseki", -"duration": 1420, -"artist": "Yuki Hayashi", -"genre": "Anime", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/vzbcsc.mp3", -"title": "Let It End", -"duration": 2220, -"artist": "Karliene", -"genre": "Folk and Indie", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/nsfwxe.mp3", -"title": "Proof Of A Hero (16 bit)", -"duration": 1410, -"artist": "Bulby", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/ywoaqa.mp3", -"title": "Proof Of A Hero", -"duration": 1340, -"artist": "Kouda Masato", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/xlrbbe.mp3", -"title": "Pure Imagination", -"duration": 2060, -"artist": "Fiona Apple", -"genre": "Electronic", -"secret": false, -"lobby": true, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/q3f6sq.mp3", -"title": "Rhapsody In Blue", -"duration": 9870, -"artist": "Kamil Hala, Slovak Philharmonic Orchestra, Libor Pešek", -"genre": "Classical and Orchestral", -"secret": false, -"lobby": true, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/vzsm5k.mp3", -"title": "Surface Of SR388", -"duration": 1710, -"artist": "BG Ollie", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/ngtv3e.mp3", -"title": "Where My Heart Will Take Me", -"duration": 0, -"artist": "Russell Watson", -"genre": "Country and Western", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/cfq7bo.mp3", -"title": "Kiss From A Rose", -"duration": 2860, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/4mypzc.mp3", -"title": "Black Hole Sun", -"duration": 3210, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/qpkv1q.mp3", -"title": "I Still Haven't Found What I'm Looking For", -"duration": 2870, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/g8vawq.mp3", -"title": "Nights In White Satin", -"duration": 2710, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/01ljjx.mp3", -"title": "Land Of Confusion", -"duration": 2850, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/2iugx4.mp3", -"title": "Aspirations", -"duration": 3010, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/m3cwu1.mp3", -"title": "Head Over Heels", -"duration": 2420, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/xtizlg.mp3", -"title": "Get Lucky", -"duration": 2490, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/dym0sp.mp3", -"title": "God Only Knows", -"duration": 1810, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/i8gml0.mp3", -"title": "Scarborough Fair", -"duration": 2020, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/chc70l.mp3", -"title": "The Sphere A Kind Of Dream", -"duration": 620, -"artist": "Dan Avidan & Super Guitar Bros", -"genre": "Acoustic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/w48oqv.mp3", -"title": "Pushin' The Speed of Light", -"duration": 2130, -"artist": "Julia Ecklar & Anne Prather", -"genre": "Folk and Indie", -"secret": false, -"lobby": true, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/zacsky.mp3", -"title": "S.T.L.", -"duration": 1190, -"artist": "Free Fall & Other Delights", -"genre": "Folk and Indie", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/9a3ow3.mp3", -"title": "Phantom Lover of the Star Drive", -"duration": 1930, -"artist": "Free Fall & Other Delights", -"genre": "Folk and Indie", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/eo59pv.mp3", -"title": "Molecular Clouds", -"duration": 1560, -"artist": "Free Fall & Other Delights", -"genre": "Folk and Indie", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/227jw9.mp3", -"title": "A Reconsideration (Zero-G Sex)", -"duration": 2530, -"artist": "Free Fall & Other Delights", -"genre": "Folk and Indie", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/yvn8bu.mp3", -"title": "Stuck Here", -"duration": 1360, -"artist": "Free Fall & Other Delights", -"genre": "Folk and Indie", -"secret": false, -"lobby": true, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/nsnf73.mp3", -"title": "The Ballad of Transport 18", -"duration": 2660, -"artist": "Leslie Fish", -"genre": "Folk and Indie", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/hwsbsi.mp3", -"title": "Don't Push That Button", -"duration": 2450, -"artist": "Duane Elms", -"genre": "Folk and Indie", -"secret": false, -"lobby": true, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/iizfw9.mp3", -"title": "Late Night at the Draco Tavern", -"duration": 2600, -"artist": "Duane Elms", -"genre": "Folk and Indie", -"secret": false, -"lobby": true, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/4zaljk.mp3", -"title": "Startide Rising", -"duration": 1050, -"artist": "Duane Elms", -"genre": "Folk and Indie", -"secret": false, -"lobby": true, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/9y01ry.mp3", -"title": "F.A.P. Feline American Princess", -"duration": 2640, -"artist": "Leslie Fish", -"genre": "Folk and Indie", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/s7u3vi.mp3", -"title": "Hymn to Breaking Strain", -"duration": 2710, -"artist": "Julia Ecklar & Leslie Fish", -"genre": "Folk and Indie", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/2t5tjk.mp3", -"title": "Waiting For The Sun", -"duration": 1910, -"artist": "Alistair Lindsay", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/8r5d7q.mp3", -"title": "Take me to Snurch (Snail Church)", -"duration": 2370, -"genre": "Pop", -"artist": "fairyeiry", -"secret": true, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/fjjcdw.mp3", -"title": "Bearded Dragon", -"duration": 2370, -"artist": "Beat Fatigue", -"genre": "Electronic", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/2dzinb.mp3", -"title": "A Good Song Never Dies", -"duration": 2010, -"artist": "Saint Motel", -"genre": "Pop", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/73nan0.mp3", -"title": "Ya Soldat", -"duration": 1880, -"artist": "5'nizza", -"genre": "Video Game", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/p1lwg8.mp3", -"title": "Space Ghost Coast to Coast", -"duration": 1880, -"artist": "Glass Animals", -"genre": "Pop", -"secret": false, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/n10l5v.mp3", -"title": "Sucklet's Song", -"duration": 1840, -"artist": "emamouse", -"genre": "Folk and Indie", -"secret": true, -"lobby": false, -"jukebox": true -}, -{ -"url": "https://files.catbox.moe/6m88w6.mp3", -"title": "King Sucklet", -"duration": 1370, -"artist": "emamouse", -"genre": "Folk and Indie", -"secret": true, -"lobby": false, -"jukebox": true -} + { + "url": "https://files.catbox.moe/notc7y.mp3", + "title": "Flip-Flap (Title One)", + "duration": 1500, + "artist": "X-CEED", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/b24m07.mp3", + "title": "Robocop Theme (Title Two)", + "duration": 1180, + "artist": "Cboyardee", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/qn5tdv.mp3", + "title": "Tin Tin on the Moon (Remix)", + "duration": 2450, + "artist": "Jeroen Tel (Remixed by Cuboos)", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/uk3pr2.mp3", + "title": "Phoron Will Make Us Rich", + "duration": 1370, + "artist": "Earthcrusher", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/k25nxo.mp3", + "title": "Spaceman's Dilemma", + "duration": 2080, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/y1dxvn.mp3", + "title": "Banned from Argo", + "duration": 3150, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/zlct4c.mp3", + "title": "Stayin' Alive", + "duration": 2420, + "artist": "The Bee Gees", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/dluppg.m4a", + "title": "Tannhauser Overture", + "duration": 9360, + "artist": "Richard Wagner", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/b4j5jc.m4a", + "title": "Another Song About the Weekend", + "duration": 2250, + "artist": "A Day to Remember", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/n36iy9.m4a", + "title": "Truly Madly Deeply", + "duration": 2770, + "artist": "Savage Garden", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/t88x7z.m4a", + "title": "Adult Education", + "duration": 3230, + "artist": "Hall and Oates", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/k38d32.mp3", + "title": "That's All", + "duration": 2640, + "artist": "Genesis", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/b59gnc.mp3", + "title": "Faith", + "duration": 1580, + "artist": "George Michael", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/twy9ln.m4a", + "title": "Last Christmas", + "duration": 2630, + "artist": "Wham!", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/m00qlo.mp3", + "title": "Dreams", + "duration": 2920, + "artist": "Van Halen", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/fwvkr7.m4a", + "title": "Geronimo's Cadillac", + "duration": 1960, + "artist": "Modern Talking", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/py8x5m.m4a", + "title": "Home Sweet Home", + "duration": 2400, + "artist": "Motley Crue", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/ius137.mp3", + "title": "Too Young to Fall in Love", + "duration": 2100, + "artist": "Motley Crue", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/dc6s20.mp3", + "title": "Working for the Weekend", + "duration": 2220, + "artist": "Loverboy", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/977069.m4a", + "title": "Miles Away", + "duration": 2520, + "artist": "Winger", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/i5q08z.m4a", + "title": "Run, Sally, Run!", + "duration": 2870, + "artist": "Carpenter Brut", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/34kdfv.mp3", + "title": "Kickstart my Heart", + "duration": 2830, + "artist": "Motley Crue", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/ul3m8e.mp3", + "title": "Bizarre Love Triangle", + "duration": 2610, + "artist": "New Order", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/8f5h2b.mp3", + "title": "Regret", + "duration": 2490, + "artist": "New Order", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/8r1ifw.m4a", + "title": "Rule Britannia Overture", + "duration": 7320, + "artist": "Richard Wagner", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/75o3mo.m4a", + "title": "Da Ya Think I'm Sexy?", + "duration": 3270, + "artist": "Rod Stewart", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/s37xwb.m4a", + "title": "Missing You", + "duration": 2690, + "artist": "John Waite", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/nayw83.mp3", + "title": "Red Velvet", + "duration": 2080, + "artist": "NicolArmarfi", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/m8qpa4.m4a", + "title": "Space Age Love Song", + "duration": 2270, + "artist": "A Flock of Seagulls", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/shjfud.m4a", + "title": "Streets of Laredo", + "duration": 1690, + "artist": "Marty Robbins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/2qdzcj.m4a", + "title": "Crockett's Theme", + "duration": 2040, + "artist": "Jan Hammer", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/8ft96j.m4a", + "title": "Take Me Home", + "duration": 3510, + "artist": "Phil Collins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/q5c942.m4a", + "title": "Moonlight Sonata", + "duration": 8990, + "artist": "Ludwig van Beethoven", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/rlutyi.m4a", + "title": "We Built This City", + "duration": 2960, + "artist": "Starship", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/1rgsqr.m4a", + "title": "A Night on Bald Mountain", + "duration": 6830, + "artist": "Modest Mussorgsky", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/frq3un.m4a", + "title": "Keep on Loving You", + "duration": 2000, + "artist": "REO Speedwagon", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/z3v10u.m4a", + "title": "Lone Star", + "duration": 1470, + "artist": "Lost Weekend Western Swing Band", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/zg7gkh.m4a", + "title": "In The Shadow of the Valley", + "duration": 1870, + "artist": "Lost Weekend Western Swing Band", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/v4xtn8.m4a", + "title": "Blue Moon", + "duration": 1710, + "artist": "Frank Sinatra", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/w2ysbr.m4a", + "title": "I Will Wait", + "duration": 2760, + "artist": "Mumford and Sons", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/jim3bp.m4a", + "title": "You Can't Hurry Love", + "duration": 1760, + "artist": "Phil Collins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/r6jh89.m4a", + "title": "Big Iron", + "duration": 2350, + "artist": "Marty Robbins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/h698sa.m4a", + "title": "Overnight Sensation", + "duration": 2380, + "artist": "Firehouse", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/bmik55.mp3", + "title": "Lightnin' Strikes Again", + "duration": 2270, + "artist": "Dokken", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/0e0wmd.m4a", + "title": "Gettin' Jiggy Wit It", + "duration": 2270, + "artist": "Will Smith", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/fm20mk.m4a", + "title": "Lay It Down", + "duration": 2050, + "artist": "Ratt", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/xogao9.m4a", + "title": "Night Fever", + "duration": 2110, + "artist": "The Bee Gees", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/8gvr40.m4a", + "title": "Robot Rock", + "duration": 2870, + "artist": "Daft Punk", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/owzo1t.m4a", + "title": "Space Jam", + "duration": 3040, + "artist": "Quad City DJs", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/t4t9qi.m4a", + "title": "Take Me Home, Country Roads", + "duration": 1980, + "artist": "John Denver", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/il9tge.m4a", + "title": "White Collar Crime", + "duration": 4620, + "artist": "Simon Viklund", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/bcniut.m4a", + "title": "Carmen Miranda's Ghost", + "duration": 1340, + "artist": "Leslie Fish", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/yg44gl.mp3", + "title": "Dawson's Christian", + "duration": 2660, + "artist": "Duane Elms", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/fhvudh.m4a", + "title": "Good Ship Manatee", + "duration": 1700, + "artist": "Leslie Fish", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/v5wm23.mp3", + "title": "Bomber", + "duration": 1920, + "artist": "Duane Elms", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/ych1i1.m4a", + "title": "Some Kind of Hero", + "duration": 4070, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/7rfftg.m4a", + "title": "Guardians", + "duration": 2370, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/yg7ndh.m4a", + "title": "One Last Battle", + "duration": 1580, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/8c3n30.m4a", + "title": "New Sins for Old", + "duration": 1520, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/t9i5vh.mp3", + "title": "Space Hero", + "duration": 1680, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/xbj8ep.mp3", + "title": "Sam Jones", + "duration": 5090, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/iiggpj.mp3", + "title": "Spacer's Home", + "duration": 2190, + "artist": "Duane Elms", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/1vowpl.m4a", + "title": "Harder, Better, Faster, Stronger", + "duration": 2260, + "artist": "Daft Punk", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/fnse07.m4a", + "title": "Crazy Train", + "duration": 2960, + "artist": "Ozzy Osbourne", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/z7b6ih.m4a", + "title": "Poison Arrow", + "duration": 2040, + "artist": "ABC", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/d874c4.m4a", + "title": "Everything Counts", + "duration": 2390, + "artist": "Depeche Mode", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/p9yfvg.m4a", + "title": "Legend Has It", + "duration": 2050, + "artist": "Run the Jewels", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/gg4pti.m4a", + "title": "Rasputin", + "duration": 2650, + "artist": "Boney M", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/u3ylxd.m4a", + "title": "Still D.R.E", + "duration": 2740, + "artist": "Dr. Dre (feat. Snoop Dogg)", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/2r3cbk.m4a", + "title": "It Was a Good Day", + "duration": 2600, + "artist": "Ice Cube", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/asthsu.m4a", + "title": "A Kiss to Build a Dream On", + "duration": 1840, + "artist": "Louis Armstrong", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/rze7qx.m4a", + "title": "(I Always Kill) The Things I Love", + "duration": 1750, + "artist": "The Real Tuesday Weld (feat. Claudia Brucken)", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/5o0uwa.mp3", + "title": "Invisible Touch", + "duration": 2080, + "artist": "Gensis", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/pdtbyi.m4a", + "title": "Tainted Love", + "duration": 1620, + "artist": "Soft Cell", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/j58vt2.mp3", + "title": "Everybody Wants To Rule The World", + "duration": 2520, + "artist": "Tears for Fears", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/llja8t.m4a", + "title": "Pink Cloud Days", + "duration": 1890, + "artist": "A.L.I.S.O.N", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/vbydgp.m4a", + "title": "Ethical Constraints Removed", + "duration": 2310, + "artist": "zircon & Jonathan Peros", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/y5tpk4.m4a", + "title": "The Blue Valley", + "duration": 7250, + "artist": "Karsten Koch", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/4vxedh.m4a", + "title": "Miami Disco", + "duration": 2700, + "artist": "Perturbator", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/dw5h51.m4a", + "title": "Shattered Dreams", + "duration": 2050, + "artist": "Johnny Hates Jazz", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/3zfcq0.mp3", + "title": "Miami", + "duration": 2730, + "artist": "Jasper Byrne", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/ecicu2.mp3", + "title": "Voyager", + "duration": 2140, + "artist": "Jasper Byrne", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/zfwxms.m4a", + "title": "Clouds of Fire", + "duration": 1170, + "artist": "Hector", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/5pl46n.m4a", + "title": "Every Day Is Night", + "duration": 2200, + "artist": "Garoad", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/0y4tjc.m4a", + "title": "Angel", + "duration": 3790, + "artist": "Massive Attack", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/ke8uk5.m4a", + "title": "Beware the Beast", + "duration": 2260, + "artist": "Carpenter Brut", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/u7yyft.m4a", + "title": "The Promise", + "duration": 2200, + "artist": "When In Rome", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/gcej08.m4a", + "title": "UNATCO - Conversation", + "duration": 1720, + "artist": "Michiel van den Bos", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/pf929m.m4a", + "title": "Virtual Insanity", + "duration": 3400, + "artist": "Jamiroquai", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/lu1gif.m4a", + "title": "Freek'n You", + "duration": 3790, + "artist": "Jodeci", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/g368sb.m4a", + "title": "And The Beat Goes On", + "duration": 4500, + "artist": "The Whispers", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/5ikte3.m4a", + "title": "Kiss From a Rose", + "duration": 2880, + "artist": "Seal", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/cqqyzj.m4a", + "title": "Sexual Healing", + "duration": 2430, + "artist": "Marvin Gaye", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/t9mwa9.m4a", + "title": "Sometimes", + "duration": 2530, + "artist": "Miami Horror", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/hdi0l9.m4a", + "title": "Nightcall", + "duration": 2580, + "artist": "Kavinsky", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/4pul1m.m4a", + "title": "Wash Away", + "duration": 2070, + "artist": "Alkaline Trio", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/whcm2r.m4a", + "title": "You Get What You Give", + "duration": 3000, + "artist": "New Radicals", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/adxl47.m4a", + "title": "Let's Dance", + "duration": 2500, + "artist": "David Bowie", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/50sksv.m4a", + "title": "Do It Again", + "duration": 3560, + "artist": "Steely Dan", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/j3ntvh.m4a", + "title": "Reelin' In The Years", + "duration": 2750, + "artist": "Steely Dan", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/utxphs.m4a", + "title": "Fire", + "duration": 1750, + "artist": "The Crazy World of Arthur Brown", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/5sh98r.m4a", + "title": "Everlong", + "duration": 2500, + "artist": "Foo Fighters", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/fdjdmj.m4a", + "title": "Limelight", + "duration": 2590, + "artist": "Rush", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/hdlhuf.m4a", + "title": "Revolution", + "duration": 2030, + "artist": "The Beatles", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/9hg3cr.m4a", + "title": "Dance the Night Away", + "duration": 1880, + "artist": "Van Halen", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/c961k1.m4a", + "title": "Blue Monday", + "duration": 4430, + "artist": "New Order", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/gldcwv.m4a", + "title": "Dancin' In the Ruins", + "duration": 2410, + "artist": "Blue Oyster Cult", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/1ckdtl.m4a", + "title": "The Boys Are Back In Town", + "duration": 2690, + "artist": "Thin Lizzy", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/w8plzv.m4a", + "title": "What It Takes", + "duration": 3110, + "artist": "Aerosmith", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/kdrv1r.m4a", + "title": "Angel", + "duration": 3080, + "artist": "Aerosmith", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/eh54mt.m4a", + "title": "Dude (Looks Like A Lady)", + "duration": 2650, + "artist": "Aerosmith", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/yczf2s.m4a", + "title": "Baba O'Riley", + "duration": 3000, + "artist": "The Who", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/v5376r.m4a", + "title": "Broken Wings", + "duration": 3430, + "artist": "Mr. Mister", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/r27dka.m4a", + "title": "Can't Fight This Feeling", + "duration": 2940, + "artist": "REO Speedwagon", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/a69sg1.m4a", + "title": "Talk Dirty To Me", + "duration": 2240, + "artist": "Poison", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/agtxnz.mp3", + "title": "Jump", + "duration": 2420, + "artist": "Van Halen", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/s8fzga.m4a", + "title": "Itz Nothin", + "duration": 2040, + "artist": "Young Roscoe", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/5qgnr9.m4a", + "title": "The Power Of Love", + "duration": 2340, + "artist": "Huey Lewis and The News", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/whbte8.m4a", + "title": "Just a Gigolo / I Ain't Got Nobody", + "duration": 2780, + "artist": "David Lee Roth", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/r32v4i.mp3", + "title": "True Faith", + "duration": 3540, + "artist": "New Order", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/oi7rov.m4a", + "title": "I Want You", + "duration": 2320, + "artist": "Savage Garden", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/tshasp.m4a", + "title": "Space Asshole", + "duration": 2340, + "artist": "Chris Remo", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/yfg6if.m4a", + "title": "Far Away", + "duration": 2810, + "artist": "Jose Gonzalez", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/6rbq2q.m4a", + "title": "All That Could Ever Be", + "duration": 3960, + "artist": "Rik Schaffer", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/l8baty.m4a", + "title": "Sleepwalking", + "duration": 2170, + "artist": "The Chain Gang of 1974", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/n6wwdu.m4a", + "title": "Take It On the Run", + "duration": 2390, + "artist": "REO Speedwagon", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/xwcipt.m4a", + "title": "Radio Ga Ga", + "duration": 3480, + "artist": "Queen", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/kq2ak3.m4a", + "title": "Dancing With Myself", + "duration": 2900, + "artist": "Billy Idol", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/ufk5gk.m4a", + "title": "Get Down Saturday Night", + "duration": 4100, + "artist": "Oliver Cheatham", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/3pvlwa.m4a", + "title": "Disco Inferno", + "duration": 2130, + "artist": "The Trammps", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/mt0w0u.mp3", + "title": "Wayfarer", + "duration": 2710, + "artist": "Kavinsky", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/wsjaml.m4a", + "title": "Papa Was A Rolling Stone", + "duration": 4180, + "artist": "The Temptations", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/ln6qoi.m4a", + "title": "I Don't Care Anymore", + "duration": 3050, + "artist": "Phil Collins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/sp6pks.m4a", + "title": "Throwing It All Away", + "duration": 2300, + "artist": "Genesis", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/1kv7kx.mp3", + "title": "In Too Deep", + "duration": 2980, + "artist": "Genesis", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/u42u20.mp3", + "title": "Easy Lover", + "duration": 3020, + "artist": "Phil Collins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/vwlu1a.mp3", + "title": "How To Be A Millionaire", + "duration": 2150, + "artist": "ABC", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/r6d520.mp3", + "title": "Hip To Be Square", + "duration": 2450, + "artist": "Huey Lewis and The News", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/i7qhge.m4a", + "title": "You've Got Another Thing Coming", + "duration": 3100, + "artist": "Judas Priest", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/16y3iy.m4a", + "title": "Live Wire", + "duration": 1940, + "artist": "Motley Crue", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/4sdesv.m4a", + "title": "Ace of Spades", + "duration": 1670, + "artist": "Motorhead", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/3qqt2v.m4a", + "title": "Rise Of The Chaos Wizards", + "duration": 2370, + "artist": "Gloryhammer", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/fgcdu2.m4a", + "title": "Turn Up the Radio", + "duration": 2780, + "artist": "Autograph", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/86ylwc.mp3", + "title": "Bark at the Moon", + "duration": 2560, + "artist": "Ozzy Osbourne", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/nfxzcn.m4a", + "title": "Cum on Feel the Noize", + "duration": 2900, + "artist": "Quiet Riot", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/gl22vl.m4a", + "title": "The Hellion / Electric Eye", + "duration": 2610, + "artist": "Judas Priest", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/j4fvlc.mp3", + "title": "2 Minutes To Midnight", + "duration": 3600, + "artist": "Iron Maiden", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/sj1o0z.m4a", + "title": "Restless Gypsy", + "duration": 2990, + "artist": "W.A.S.P", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/lkkq00.m4a", + "title": "Universe On Fire", + "duration": 2460, + "artist": "Gloryhammer", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/ftmgxf.m4a", + "title": "Girls, Girls, Girls", + "duration": 2700, + "artist": "Motley Crue", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/uciolb.m4a", + "title": "To Hell with the Devil", + "duration": 2440, + "artist": "Stryper", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/6x9zur.m4a", + "title": "God Blessed Video", + "duration": 2100, + "artist": "Alcatrazz", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/gmgh6w.m4a", + "title": "Cumin' Atcha Live", + "duration": 2660, + "artist": "Tesla", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/zti66s.m4a", + "title": "Heavy Metal: The Black and Silver", + "duration": 2000, + "artist": "Blue Oyster Cult", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/8ew21k.m4a", + "title": "Mars For The Rich", + "duration": 2510, + "artist": "King Gizzard & the Lizard Wizard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/di9apc.m4a", + "title": "Insane in the Membrane", + "duration": 2100, + "artist": "Cypress Hill", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/8nyu9s.m4a", + "title": "Just a Friend", + "duration": 2380, + "artist": "Biz Markie", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/2b0wu2.m4a", + "title": "Intergalactic", + "duration": 2290, + "artist": "Beastie Boys", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/nv66ck.mp3", + "title": "Wild Child", + "duration": 3120, + "artist": "W.A.S.P", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/z3k8rs.m4a", + "title": "Icarus' Dream Suite Op.4", + "duration": 5140, + "artist": "Yngwie Malmsteen", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/57ghcq.m4a", + "title": "Fantasy", + "duration": 3030, + "artist": "Aldo Nova", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/kwwvsg.m4a", + "title": "Nocturne Op.9 No.2", + "duration": 2690, + "artist": "Frederic Chopin", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/zab3he.mp3", + "title": "Concord", + "duration": 1850, + "artist": "NicolArmarfi & Blue123", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/e52gys.mp3", + "title": "Clair de Lune", + "duration": 3570, + "artist": "Claude Debussy", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/e7nk9a.mp3", + "title": "Gymnopedie No.1", + "duration": 1870, + "artist": "Erik Satie", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/wf7jr8.mp3", + "title": "Johans Waltz", + "duration": 2860, + "artist": "Andreas Waldetoft", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/15ybh9.mp3", + "title": "Handel This", + "duration": 890, + "artist": "Andreas Waldetoft", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/0294ze.m4a", + "title": "Lohengrin: Prelude", + "duration": 5930, + "artist": "Richard Wagner", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/xgq1tr.m4a", + "title": "Concerto Grosso no. 10 in B Minor - Allegro", + "duration": 2150, + "artist": "Antonio Vivaldi", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/vxe2qt.m4a", + "title": "Ancient Stones", + "duration": 2850, + "artist": "Jeremy Soule", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/8bdxq3.m4a", + "title": "Secunda", + "duration": 1230, + "artist": "Jeremy Soule", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/lqgoiv.m4a", + "title": "Far Horizons", + "duration": 3310, + "artist": "Jeremy Soule", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/azzap9.mp3", + "title": "Time of Change", + "duration": 2020, + "artist": "FlybyNo", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/m67gzk.m4a", + "title": "Dreamer's Rest", + "duration": 2380, + "artist": "Vindsvept", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/tnx2fb.mp3", + "title": "Moment of Decision", + "duration": 2430, + "artist": "NicolArmarfi", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Classical and Orchestral" + }, + { + "url": "https://files.catbox.moe/c7yeau.mp3", + "title": "In My Dreams", + "duration": 2600, + "artist": "Dokken", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/u8xh6b.m4a", + "title": "Wasted Years", + "duration": 3090, + "artist": "Iron Maiden", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/utjagr.m4a", + "title": "Round and Round", + "duration": 2650, + "artist": "Ratt", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/mbzbla.m4a", + "title": "Crystal Ball", + "duration": 2950, + "artist": "Yngwie Malmsteen", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/p9cnth.m4a", + "title": "I Remember You", + "duration": 3130, + "artist": "Skid Row", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/pkhotw.m4a", + "title": "I Won't Forget You", + "duration": 2150, + "artist": "Poison", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/231ksl.m4a", + "title": "Pjanoo (Club Mix)", + "duration": 4500, + "artist": "Eric Prydz", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/58hrry.m4a", + "title": "Inferno Galore", + "duration": 2250, + "artist": "Carpenter Brut", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/vsdg7v.m4a", + "title": "Low Rider", + "duration": 1910, + "artist": "War", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/gu2yfz.m4a", + "title": "How Deep Is Your Love", + "duration": 2450, + "artist": "The Bee Gees", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/slm18k.m4a", + "title": "You Dropped A Bomb On Me", + "duration": 3120, + "artist": "The Gap Band", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/24cqmw.m4a", + "title": "Every Rose Has It's Thorn", + "duration": 2600, + "artist": "Poison", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/v3otpl.m4a", + "title": "Fallen Angel", + "duration": 2380, + "artist": "Poison", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/iezn71.m4a", + "title": "Baby Hold On", + "duration": 2100, + "artist": "Eddie Money", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/e8w3ym.m4a", + "title": "Two Tickets To Paradise", + "duration": 2370, + "artist": "Eddie Money", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/cavpff.m4a", + "title": "Take Me Home Tonight", + "duration": 2110, + "artist": "Eddie Money", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/n8l93a.m4a", + "title": "Same Ol' Situation (S.O.S.)", + "duration": 2530, + "artist": "Motely Crue", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/gnr6py.m4a", + "title": "Metal Health (Bang Your Head)", + "duration": 3160, + "artist": "Quiet Riot", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/1drakx.m4a", + "title": "Shout At The Devil", + "duration": 1950, + "artist": "Motley Crue", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/1kevft.m4a", + "title": "Walk With Me in Hell", + "duration": 3110, + "artist": "Lamb of God", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/9cdsmd.m4a", + "title": "Crazy (A Suitable Case For Treatment)", + "duration": 2070, + "artist": "Nazareth", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/6oq1qw.m4a", + "title": "Freezing Moon", + "duration": 3830, + "artist": "Mayhem", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/jrc74a.m4a", + "title": "Raining Blood", + "duration": 2540, + "artist": "Slayer", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/ey07dt.m4a", + "title": "Marching Off to War", + "duration": 2490, + "artist": "Motorhead", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/a77r2l.m4a", + "title": "Hymn Of The Forsaken", + "duration": 3880, + "artist": "Climmhazard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/omm3y6.m4a", + "title": "Victory Song", + "duration": 6390, + "artist": "Ensiferum", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/sx7kbr.m4a", + "title": "Dunkelheit", + "duration": 4210, + "artist": "Burzum", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/r6uftn.m4a", + "title": "Sick Bubblegum", + "duration": 2240, + "artist": "Rob Zombie", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/ysee6q.m4a", + "title": "Laser Enforcer", + "duration": 2540, + "artist": "Slough Feg", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/sxcus4.m4a", + "title": "Veteran of the Psychic Wars", + "duration": 2890, + "artist": "Blue Oyster Cult", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/qkxavx.m4a", + "title": "Tiger! Tiger!", + "duration": 2530, + "artist": "Slough Feg", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/u7rhxc.m4a", + "title": "Hyperdrive", + "duration": 2140, + "artist": "The Devin Townsend Project", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/narev2.m4a", + "title": "Judas", + "duration": 2500, + "artist": "Fozzy", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/pguvz2.m4a", + "title": "Alone Again", + "duration": 2600, + "artist": "Dokken", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/0gol3u.m4a", + "title": "Superbeast", + "duration": 2200, + "artist": "Rob Zombie", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/irrxal.m4a", + "title": "Perihelion", + "duration": 1910, + "artist": "King Gizzard & The Lizard Wizard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/f9yw8d.m4a", + "title": "Self-Immolate", + "duration": 2680, + "artist": "King Gizzard & The Lizard Wizard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/zmyym2.m4a", + "title": "Planet B", + "duration": 2360, + "artist": "King Gizzard & The Lizard Wizard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/isa0lb.m4a", + "title": "On The Wind", + "duration": 2250, + "artist": "Dream Evil", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/oi9dt1.m4a", + "title": "Catch The Rainbow", + "duration": 3960, + "artist": "Rainbow", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/1ozes3.m4a", + "title": "Peace Sells", + "duration": 2440, + "artist": "Megadeth", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Metal" + }, + { + "url": "https://files.catbox.moe/iyi2ll.m4a", + "title": "Never Gonna Give You Up", + "duration": 2130, + "artist": "Rick Astley", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/s46vw9.m4a", + "title": "I Fought The Law", + "duration": 1630, + "artist": "The Clash", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/3blefo.m4a", + "title": "Piano Man", + "duration": 3400, + "artist": "Billy Joel", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/qq4cbx.m4a", + "title": "Mr. Blue Sky", + "duration": 3030, + "artist": "Electric Light Orchestra", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/uxwl09.m4a", + "title": "Here I Go Again (1987 Version)", + "duration": 2750, + "artist": "Whitesnake", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/jgigel.m4a", + "title": "Starman", + "duration": 2540, + "artist": "David Bowie", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/nq2w6w.m4a", + "title": "Space Oddity", + "duration": 3180, + "artist": "David Bowie", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/2n2gdq.m4a", + "title": "Changes", + "duration": 2170, + "artist": "David Bowie", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/jzucsv.mp3", + "title": "A Horse With No Name", + "duration": 2470, + "artist": "America", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/d05y2k.m4a", + "title": "Space Oddity (Cover)", + "duration": 3330, + "artist": "Chris Hadfield", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/1gbbu1.m4a", + "title": "Cruel, Cruel World (Josh Homme)", + "duration": 2140, + "artist": "Josh Homme", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/3941ms.m4a", + "title": "House Building", + "duration": 2200, + "artist": "David 'Fergie' Ferguson", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/rf6v2o.m4a", + "title": "Folsom Prison Blues", + "duration": 1680, + "artist": "Johnny Cash", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/1deyd1.m4a", + "title": "A White Sport Coat (And a Pink Carnation)", + "duration": 1480, + "artist": "Marty Robbins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/r7asbn.m4a", + "title": "Lovers Of The World", + "duration": 1680, + "artist": "Jerry Wallace", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/gdd5v3.m4a", + "title": "Cruel, Cruel World (Willie Nelson)", + "duration": 2660, + "artist": "Willie Nelson", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/vrj0cl.m4a", + "title": "The Story Of A Soldier", + "duration": 2390, + "artist": "Ennio Morricone", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/wdswuf.m4a", + "title": "Rawhide", + "duration": 1200, + "artist": "Frankie Laine", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/sa9lg3.m4a", + "title": "Psycho", + "duration": 2160, + "artist": "Eddie Noack", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/j84ln2.m4a", + "title": "Before You Use That Gun", + "duration": 1520, + "artist": "Eddie Noack", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/3ae5p2.m4a", + "title": "Rhinestone Cowboy", + "duration": 2090, + "artist": "Glen Campbell", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/hbc1vd.m4a", + "title": "Flowers on the Wall", + "duration": 1390, + "artist": "The Statler Brothers", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/7ibtm1.m4a", + "title": "Bed Of Roses", + "duration": 1480, + "artist": "The Statler Brothers", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/mv8xql.m4a", + "title": "New York City", + "duration": 1710, + "artist": "The Statler Brothers", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/5mtinr.m4a", + "title": "The Devil Went Down to Georgia", + "duration": 2140, + "artist": "The Charlie Daniels Band", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/qvd0qg.m4a", + "title": "Cottonwood Tree", + "duration": 2370, + "artist": "Marty Robbins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/378qb4.m4a", + "title": "Ain't I Right", + "duration": 1980, + "artist": "Marty Robbins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/5sgpkn.m4a", + "title": "Wish It Was True", + "duration": 2280, + "artist": "The White Buffalo", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/de3b29.m4a", + "title": "Burn The Witch", + "duration": 2480, + "artist": "Shawn James", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/av3j0o.m4a", + "title": "Sink The Bismarck", + "duration": 1940, + "artist": "Johnny Horton", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/8z0ueu.m4a", + "title": "Mr. Shorty", + "duration": 3030, + "artist": "Marty Robbins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/0wwk0d.m4a", + "title": "Uneasy Rider", + "duration": 3180, + "artist": "The Charlie Daniels Band", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/dws0dz.m4a", + "title": "Uneasy Rider '88", + "duration": 2640, + "artist": "The Charlie Daniels Band", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/ci1gka.m4a", + "title": "For A Few Dollars More", + "duration": 1680, + "artist": "Ennio Morricone", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Country and Western" + }, + { + "url": "https://files.catbox.moe/pbw43i.m4a", + "title": "Faster Than Light", + "duration": 2370, + "artist": "Ben Prunty", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/va5a54.m4a", + "title": "Rebecca", + "duration": 2540, + "artist": "Tesla Boy", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/g3mwvn.m4a", + "title": "Zero Point Non-Response", + "duration": 3330, + "artist": "Mega Drive", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/fu3mf9.m4a", + "title": "Edge of Reality", + "duration": 3300, + "artist": "Mega Drive", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/nspw3i.m4a", + "title": "What Is Love", + "duration": 2700, + "artist": "Haddaway", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/8kyy4o.mp3", + "title": "Time Lapse", + "duration": 2600, + "artist": "Kalax", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/yuwdr5.m4a", + "title": "So Far Away", + "duration": 2820, + "artist": "Lazerhawk", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/hlsk69.m4a", + "title": "Children of the Omnissiah", + "duration": 1060, + "artist": "Guillaume David", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/t7q36u.m4a", + "title": "Noosphere", + "duration": 3880, + "artist": "Guillaume David", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/e2lxd4.m4a", + "title": "Resonance", + "duration": 2120, + "artist": "HOME", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/fnngli.m4a", + "title": "We're Finally Landing", + "duration": 2720, + "artist": "HOME", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/36juno.mp3", + "title": "Head First", + "duration": 2130, + "artist": "HOME", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/bvwhm0.m4a", + "title": "Dust", + "duration": 3020, + "artist": "M|O|O|N", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/b6urx6.m4a", + "title": "Silent Strike", + "duration": 2970, + "artist": "Garth Knight", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/ywr4gd.mp3", + "title": "Night Train", + "duration": 2440, + "artist": "Mitch Murder", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/rgtjn3.m4a", + "title": "Welcome to VA-11 Hall-A", + "duration": 1880, + "artist": "Garoad", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/86wwz1.m4a", + "title": "Drive Me Wild", + "duration": 2280, + "artist": "Garoad", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/j14cpw.m4a", + "title": "Sexualizer", + "duration": 2990, + "artist": "Perturbator (feat. Flash Arnold)", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/3zb1hx.m4a", + "title": "Into The Labyrinth", + "duration": 3100, + "artist": "Kraddy", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/qxadpn.m4a", + "title": "Turbo Killer", + "duration": 2080, + "artist": "Carpenter Brut", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/dclq52.m4a", + "title": "Deep Cover", + "duration": 4850, + "artist": "Sun Araw", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/wpws58.m4a", + "title": "Fragments of Bach I", + "duration": 3060, + "artist": "Compilerbau", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/ltlzpi.mp3", + "title": "Leather Teeth", + "duration": 2330, + "artist": "Carpenter Brut", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/bem2ur.m4a", + "title": "Cheerleader Effect", + "duration": 2170, + "artist": "Carpenter Brut", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/hwfg7e.m4a", + "title": "Hairspray Hurricane", + "duration": 3310, + "artist": "Carpenter Brut", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/xx00ka.m4a", + "title": "Sunday Lunch", + "duration": 1950, + "artist": "Carpenter Brut", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/4ju4p1.mp3", + "title": "Lone Digger", + "duration": 2300, + "artist": "Caravan Palace", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/4c0lmk.m4a", + "title": "Dessert", + "duration": 1840, + "artist": "Jun Chikuma", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/g0ms06.m4a", + "title": "Propane Nightmares", + "duration": 3130, + "artist": "Pendulum", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/7i23kv.m4a", + "title": "Overdrive (Instrumental)", + "duration": 2260, + "artist": "Lily Arciniega", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/re4is1.m4a", + "title": "Tusk", + "duration": 2180, + "artist": "Fleetwood Mac", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/xztay0.m4a", + "title": "Rock On Rockall", + "duration": 1740, + "artist": "The Wolfe Tones", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/6ryyk0.m4a", + "title": "Apocalypse", + "duration": 2900, + "artist": "Cigarettes After Sex", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/2z6lpx.mp3", + "title": "Pioneer's Song", + "duration": 1790, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/e55ey0.mp3", + "title": "Bones", + "duration": 1200, + "artist": "Leslie Fish", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Folk and Indie" + }, + { + "url": "https://files.catbox.moe/evilyr.m4a", + "title": "Age of Consent", + "duration": 3150, + "artist": "New Order", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/lgot68.m4a", + "title": "Maneater", + "duration": 2730, + "artist": "Hall & Oates", + "secret": false, + "lobby": true, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/8e4bb0.m4a", + "title": "Ordinary World", + "duration": 3400, + "artist": "Duran Duran", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/leulle.m4a", + "title": "Forever Young", + "duration": 2260, + "artist": "Alphaville", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/z8bxjp.m4a", + "title": "Sussudio", + "duration": 2640, + "artist": "Phil Collins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/wti40y.m4a", + "title": "One More Night", + "duration": 2910, + "artist": "Phil Collins", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/zifzgk.m4a", + "title": "Little Girls", + "duration": 2230, + "artist": "Oingo Boingo", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/5yk0mm.m4a", + "title": "Everything She Wants", + "duration": 3920, + "artist": "Wham!", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/5ye8et.m4a", + "title": "Careless Whisper", + "duration": 3030, + "artist": "George Michael", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/9a5dov.m4a", + "title": "Space Cowboy", + "duration": 2160, + "artist": "Jamiroquai", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Disco, Funk, Soul, and R&B" + }, + { + "url": "https://files.catbox.moe/dpjb9r.m4a", + "title": "Video Killed The Radio Star", + "duration": 2530, + "artist": "The Buggles", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/367b33.m4a", + "title": "Honey, There's No Time", + "duration": 2610, + "artist": "Feng Suave", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/q5kk5l.m4a", + "title": "Sink into the Floor", + "duration": 2790, + "artist": "Feng Suave", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/w7d9qk.m4a", + "title": "This Train", + "duration": 2850, + "artist": "Turk Murphy's San Francisco Jazz Band", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/79d8gs.mp3", + "title": "Love Theme", + "duration": 5710, + "artist": "Andrew Hale", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/u1h4vg.m4a", + "title": "Jingle Jangle Jingle", + "duration": 1970, + "artist": "Kay Kyser", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/ky7dvn.m4a", + "title": "Personality", + "duration": 1690, + "artist": "Johnny Mercer & The Pied Pipers", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/5jm318.m4a", + "title": "Let's Face The Music And Dance", + "duration": 1710, + "artist": "Frank Sinatra", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/jhjidm.m4a", + "title": "I'll Get By", + "duration": 1700, + "artist": "Frank Fontaine", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/bwg49y.m4a", + "title": "That Face!", + "duration": 1430, + "artist": "Frank Sinatra Jr", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/2wmc3x.m4a", + "title": "Mack the Knife", + "duration": 1840, + "artist": "Bobby Darin", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/q2t0i0.m4a", + "title": "The Day The Clown Cried", + "duration": 1900, + "artist": "Jimmy Beaumont & The Skyliners", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/c06zik.m4a", + "title": "Invitation To The Blues", + "duration": 3240, + "artist": "Tom Waits", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/1z0mli.m4a", + "title": "Drunk On The Moon", + "duration": 3060, + "artist": "Tom Waits", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/dqu0t5.m4a", + "title": "La Vie En Rose", + "duration": 2050, + "artist": "Louis Armstrong", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/0ys4q8.m4a", + "title": "So What", + "duration": 5690, + "artist": "Miles Davis Sextet", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/nr7btw.m4a", + "title": "Just The Two Of Us", + "duration": 4430, + "artist": "Grover Washington Jr", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/tb9ys2.m4a", + "title": "Quiet Nights Of Quiet Stars", + "duration": 1640, + "artist": "Frank Sinatra & Antonio Carlos Jobim", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/zd1sw1.m4a", + "title": "Drinking Water", + "duration": 1530, + "artist": "Frank Sinatra & Antonio Carlos Jobim", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/fwtdoh.m4a", + "title": "Ol' Man River (Showboat)", + "duration": 2340, + "artist": "Paul Robseon", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Jazz" + }, + { + "url": "https://files.catbox.moe/mp8tab.m4a", + "title": "Juke Box Hero", + "duration": 2590, + "artist": "Foreigner", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/n0ezuw.m4a", + "title": "Waiting for a Girl Like You", + "duration": 2890, + "artist": "Foreigner", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/gd49uk.m4a", + "title": "I Want to Know What Love Is", + "duration": 3040, + "artist": "Foreigner", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/s36f97.m4a", + "title": "She Sells Sanctuary", + "duration": 2620, + "artist": "The Cult", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/62lks9.m4a", + "title": "No One Knows", + "duration": 2580, + "artist": "Queens of the Stone Age", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/e4sltu.m4a", + "title": "Like a Stone", + "duration": 2940, + "artist": "Audioslave", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/yitsz9.m4a", + "title": "Friday I'm in Love", + "duration": 2140, + "artist": "The Cure", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Pop" + }, + { + "url": "https://files.catbox.moe/dwyjkt.m4a", + "title": "Ozymandias", + "duration": 1920, + "artist": "Red Vox", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/wmpgcr.mp3", + "title": "Welcome To The Jungle", + "duration": 2690, + "artist": "Guns N' Roses", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/20exnb.mp3", + "title": "Fortunate Son", + "duration": 1400, + "artist": "Creedence Clearwater Revival", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/8xzmw5.mp3", + "title": "Bohemian Rhapsody", + "duration": 3580, + "artist": "Queen", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/7x2cvf.mp3", + "title": "Rocket Man", + "duration": 2820, + "artist": "Elton John", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/xjgch6.m4a", + "title": "Smooth Sailing", + "duration": 2910, + "artist": "Queens of the Stone Age", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/f8ebif.m4a", + "title": "Face Melter (How to Do Impossible Things)", + "duration": 2100, + "artist": "Death Grips", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/6i31kh.m4a", + "title": "Rapper's Delight", + "duration": 8850, + "artist": "The Sugar Hill Gang", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/3y9k43.m4a", + "title": "Super Freak", + "duration": 2020, + "artist": "Rick James", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/93ynna.m4a", + "title": "Party All The Time", + "duration": 2530, + "artist": "Eddie Murphy", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/4s8xyr.m4a", + "title": "Funky Cold Medina", + "duration": 2480, + "artist": "Tone-Loc", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/jzpkv4.m4a", + "title": "Children's Story", + "duration": 2420, + "artist": "Slick Rick", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/tk1zno.m4a", + "title": "Voila", + "duration": 2080, + "artist": "Death Grips", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/jvhl18.m4a", + "title": "Black Ballons Reprise", + "duration": 1620, + "artist": "Flying Lotus (feat. Denzel Curry)", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/59nnfc.m4a", + "title": "Take_it_Back_v2", + "duration": 1690, + "artist": "Denzel Curry & Kenny Beats", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/pkwkd1.m4a", + "title": "All Caps", + "duration": 1340, + "artist": "Madvillain", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/d7zx95.m4a", + "title": "Express Yourself", + "duration": 2650, + "artist": "N.W.A", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/fgn4pf.m4a", + "title": "BLACK BALLOONS", + "duration": 2100, + "artist": "Denzel Curry", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/o7hb3j.m4a", + "title": "Meat Grinder", + "duration": 1310, + "artist": "Madvillain", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Hip-Hop and Rap" + }, + { + "url": "https://files.catbox.moe/8o0z0l.m4a", + "title": "Keep Your Eyes Peeled", + "duration": 3040, + "artist": "Queens of the Stone Age", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/ri8l16.m4a", + "title": "Sleep Drifter", + "duration": 2840, + "artist": "King Gizzard & The Lizard Wizard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/zz1p3n.m4a", + "title": "Open Water", + "duration": 4330, + "artist": "King Gizzard & The Lizard Wizard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/prllpr.m4a", + "title": "Gamma Knife", + "duration": 2910, + "artist": "King Gizzard & The Lizard Wizard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/v66qvy.m4a", + "title": "Baby Gotterdammerung", + "duration": 1880, + "artist": "Monster Magnet", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/isus1b.m4a", + "title": "Robot Stop", + "duration": 2100, + "artist": "King Gizzard & The Lizard Wizard", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/qhionp.mp3", + "title": "Come Sail Away", + "duration": 3650, + "artist": "Styx", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/vm93di.m4a", + "title": "Bullet Girl", + "duration": 3210, + "artist": "John Butler Trio", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/f3gvmk.m4a", + "title": "Holland, 1945", + "duration": 1920, + "artist": "Neutral Milk Hotel", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Rock" + }, + { + "url": "https://files.catbox.moe/8rn8uz.mp3", + "title": "I Wupped Batman's Ass", + "duration": 3270, + "genre": "Miscellaneous", + "artist": "Wesley Willis Fiasco", + "secret": true, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/h967s5.mp3", + "title": "MEGALOVANIA", + "duration": 1416, + "artist": "Toby Fox", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Video Game" + }, + { + "url": "https://files.catbox.moe/yumfgs.mp3", + "title": "ASGORE", + "duration": 1416, + "artist": "Toby Fox", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Video Game" + }, + { + "url": "https://files.catbox.moe/ewn2u4.mp3", + "title": "Disco Descent", + "duration": 1800, + "artist": "Danny Baranowsky", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/8rns1d.mp3", + "title": "Konga Conga Kappa", + "duration": 1130, + "artist": "Danny Baranowsky", + "secret": false, + "lobby": false, + "jukebox": true, + "genre": "Electronic" + }, + { + "url": "https://files.catbox.moe/3h38kn.mp3", + "title": "Among Us", + "duration": 720, + "artist": "Leonz", + "genre": "Disco, Funk, Soul, and R&B", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/rqhxj1.mp3", + "title": "Leggy Zone", + "duration": 1470, + "artist": "Binox", + "genre": "Electronic", + "secret": true, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/e6l6mw.mp3", + "title": "Shop Theme", + "duration": 8910, + "artist": "Kazumi Totaka/Nintendo", + "genre": "Electronic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/q2ob3n.mp3", + "title": "PONPONPON", + "duration": 2430, + "artist": "Kyary Pamyu Pamyu", + "genre": "J-Pop", + "secret": false, + "lobby": false + }, + { + "url": "https://files.catbox.moe/o8flhu.mp3", + "title": "Man's Road", + "duration": 2060, + "artist": "America", + "genre": "Rock", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/0gb5qs.mp3", + "title": "Passionflower", + "duration": 3840, + "artist": "Jon Gomm", + "genre": "Rock", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/p5e28z.mp3", + "title": "What the Fuck", + "duration": 2420, + "artist": "Koh", + "genre": "Folk and Indie", + "secret": true, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/0f2xma.mp3", + "title": "Bonetrousle", + "duration": 580, + "artist": "Toby Fox", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/6ivc7w.mp3", + "title": "Bury the Light", + "duration": 5830, + "artist": "Victor Borba & Casey Edwards", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/pbtbjv.mp3", + "title": "Dog Song", + "duration": 380, + "artist": "Toby Fox", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/4v3eeb.mp3", + "title": "Anticipation", + "duration": 230, + "artist": "Toby Fox", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/0q8ch6.mp3", + "title": "Smash Clown", + "duration": 820, + "artist": "Goat", + "genre": "Space", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/ygcg2e.mp3", + "title": "Honk The Police", + "duration": 590, + "artist": "Goat", + "genre": "Space", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/h0yswi.mp3", + "title": "Cargonia", + "duration": 630, + "artist": "Goat", + "genre": "Space", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/xg76ja.mp3", + "title": "Hail Cargonia", + "duration": 980, + "artist": "Goat", + "genre": "Space", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/tbr2rc.mp3", + "title": "Banned From Cargo", + "duration": 2450, + "artist": "Goat", + "genre": "Space", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/tw2et2.mp3", + "title": "Periphery Dixie", + "duration": 1200, + "artist": "Goat", + "genre": "Space", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/rm5hcs.mp3", + "title": "Cargonia (cover)", + "duration": 2730, + "artist": "Dadbot5000", + "genre": "Space", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/ybfof9.mp3", + "title": "The Legend", + "duration": 1120, + "artist": "Toby Fox", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/ugfx06.mp3", + "title": "Field of Hopes and Dreams", + "duration": 1610, + "artist": "Toby Fox", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/wr08om.mp3", + "title": "Checker Dance", + "duration": 780, + "artist": "Toby Fox", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/4au954.mp3", + "title": "Vs Susie", + "duration": 810, + "artist": "Toby Fox", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/c9y5x2.mp3", + "title": "Golden Wind", + "duration": 2930, + "artist": "Yugo Kanno", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/ymvtem.mp3", + "title": "Sono Chi no Sadame", + "duration": 2610, + "artist": "Hiroaki TOMMY Tominaga", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/z73u05.mp3", + "title": "Bloody Stream", + "duration": 2590, + "artist": "Coda", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/yg3643.mp3", + "title": "Stand Proud", + "duration": 2750, + "artist": "Jin Hashimoto", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/344qrf.mp3", + "title": "Sono Chi no Kioku ~end of THE WORLD~", + "duration": 2620, + "artist": "JO☆STARS", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/0n6y6v.mp3", + "title": "Crazy Noisy Bizarre Town", + "duration": 1840, + "artist": "THE DU", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/j3xzw6.mp3", + "title": "Chase", + "duration": 1450, + "artist": "Batta", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/luf1bh.mp3", + "title": "Great Days", + "duration": 2400, + "artist": "Karen Aoki & Daisuke Hasegaw", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/ytp4d2.mp3", + "title": "Fighting Gold", + "duration": 2540, + "artist": "Coda", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/q1xjdp.mp3", + "title": "I Want It That Way", + "duration": 2120, + "artist": "Backstreet Boys", + "genre": "Pop", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/pxpkat.mp3", + "title": "Shop Theme Cover", + "duration": 1770, + "artist": "Songe", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/nz03o1.mp3", + "title": "Deep Space 9 (Cover)", + "duration": 1220, + "artist": "Heropoint", + "genre": "Rock", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/n4vcnq.mp3", + "title": "Trouble Shooting Star", + "duration": 1460, + "artist": "", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/byy378.mp3", + "title": "The Lord of the Rings The Fellowship of the its my book they will walk if I tell them to", + "duration": 970, + "artist": "Tom Cardy", + "genre": "Folk and Indie", + "secret": true, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/akgbup.mp3", + "title": "Flight of the Bumblebee", + "duration": 2050, + "artist": "Rimsky Korsakov", + "genre": "Classical and Orchestral", + "secret": true, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/milk8o.mp3", + "title": "As Heaven Is Wide", + "duration": 2880, + "artist": "Garbage", + "genre": "Rock", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/8mh82l.mp3", + "title": "Combat Montage", + "duration": 1410, + "artist": "Kevin Manthei", + "genre": "Rock", + "secret": true, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/qa6ahi.mp3", + "title": "Deadlines", + "duration": 1570, + "artist": "Network Music Ensemble", + "genre": "Rock", + "secret": false, + "lobby": true, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/cdmm5k.mp3", + "title": "Holding Out For A Hero", + "duration": 2620, + "artist": "Ella Mae Bowen", + "genre": "Country and Western", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/jlv9eb.mp3", + "title": "Jiko Bunseki", + "duration": 1420, + "artist": "Yuki Hayashi", + "genre": "Anime", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/vzbcsc.mp3", + "title": "Let It End", + "duration": 2220, + "artist": "Karliene", + "genre": "Folk and Indie", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/nsfwxe.mp3", + "title": "Proof Of A Hero (16 bit)", + "duration": 1410, + "artist": "Bulby", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/ywoaqa.mp3", + "title": "Proof Of A Hero", + "duration": 1340, + "artist": "Kouda Masato", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/xlrbbe.mp3", + "title": "Pure Imagination", + "duration": 2060, + "artist": "Fiona Apple", + "genre": "Electronic", + "secret": false, + "lobby": true, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/q3f6sq.mp3", + "title": "Rhapsody In Blue", + "duration": 9870, + "artist": "Kamil Hala, Slovak Philharmonic Orchestra, Libor Pešek", + "genre": "Classical and Orchestral", + "secret": false, + "lobby": true, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/vzsm5k.mp3", + "title": "Surface Of SR388", + "duration": 1710, + "artist": "BG Ollie", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/ngtv3e.mp3", + "title": "Where My Heart Will Take Me", + "duration": 0, + "artist": "Russell Watson", + "genre": "Country and Western", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/cfq7bo.mp3", + "title": "Kiss From A Rose", + "duration": 2860, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/4mypzc.mp3", + "title": "Black Hole Sun", + "duration": 3210, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/qpkv1q.mp3", + "title": "I Still Haven't Found What I'm Looking For", + "duration": 2870, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/g8vawq.mp3", + "title": "Nights In White Satin", + "duration": 2710, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/01ljjx.mp3", + "title": "Land Of Confusion", + "duration": 2850, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/2iugx4.mp3", + "title": "Aspirations", + "duration": 3010, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/m3cwu1.mp3", + "title": "Head Over Heels", + "duration": 2420, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/xtizlg.mp3", + "title": "Get Lucky", + "duration": 2490, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/dym0sp.mp3", + "title": "God Only Knows", + "duration": 1810, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/i8gml0.mp3", + "title": "Scarborough Fair", + "duration": 2020, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/chc70l.mp3", + "title": "The Sphere A Kind Of Dream", + "duration": 620, + "artist": "Dan Avidan & Super Guitar Bros", + "genre": "Acoustic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/w48oqv.mp3", + "title": "Pushin' The Speed of Light", + "duration": 2130, + "artist": "Julia Ecklar & Anne Prather", + "genre": "Folk and Indie", + "secret": false, + "lobby": true, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/zacsky.mp3", + "title": "S.T.L.", + "duration": 1190, + "artist": "Free Fall & Other Delights", + "genre": "Folk and Indie", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/9a3ow3.mp3", + "title": "Phantom Lover of the Star Drive", + "duration": 1930, + "artist": "Free Fall & Other Delights", + "genre": "Folk and Indie", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/eo59pv.mp3", + "title": "Molecular Clouds", + "duration": 1560, + "artist": "Free Fall & Other Delights", + "genre": "Folk and Indie", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/227jw9.mp3", + "title": "A Reconsideration (Zero-G Sex)", + "duration": 2530, + "artist": "Free Fall & Other Delights", + "genre": "Folk and Indie", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/yvn8bu.mp3", + "title": "Stuck Here", + "duration": 1360, + "artist": "Free Fall & Other Delights", + "genre": "Folk and Indie", + "secret": false, + "lobby": true, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/nsnf73.mp3", + "title": "The Ballad of Transport 18", + "duration": 2660, + "artist": "Leslie Fish", + "genre": "Folk and Indie", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/hwsbsi.mp3", + "title": "Don't Push That Button", + "duration": 2450, + "artist": "Duane Elms", + "genre": "Folk and Indie", + "secret": false, + "lobby": true, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/iizfw9.mp3", + "title": "Late Night at the Draco Tavern", + "duration": 2600, + "artist": "Duane Elms", + "genre": "Folk and Indie", + "secret": false, + "lobby": true, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/4zaljk.mp3", + "title": "Startide Rising", + "duration": 1050, + "artist": "Duane Elms", + "genre": "Folk and Indie", + "secret": false, + "lobby": true, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/9y01ry.mp3", + "title": "F.A.P. Feline American Princess", + "duration": 2640, + "artist": "Leslie Fish", + "genre": "Folk and Indie", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/s7u3vi.mp3", + "title": "Hymn to Breaking Strain", + "duration": 2710, + "artist": "Julia Ecklar & Leslie Fish", + "genre": "Folk and Indie", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/2t5tjk.mp3", + "title": "Waiting For The Sun", + "duration": 1910, + "artist": "Alistair Lindsay", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/8r5d7q.mp3", + "title": "Take me to Snurch (Snail Church)", + "duration": 2370, + "genre": "Pop", + "artist": "fairyeiry", + "secret": true, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/fjjcdw.mp3", + "title": "Bearded Dragon", + "duration": 2370, + "artist": "Beat Fatigue", + "genre": "Electronic", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/2dzinb.mp3", + "title": "A Good Song Never Dies", + "duration": 2010, + "artist": "Saint Motel", + "genre": "Pop", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/73nan0.mp3", + "title": "Ya Soldat", + "duration": 1880, + "artist": "5'nizza", + "genre": "Video Game", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/p1lwg8.mp3", + "title": "Space Ghost Coast to Coast", + "duration": 1880, + "artist": "Glass Animals", + "genre": "Pop", + "secret": false, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/n10l5v.mp3", + "title": "Sucklet's Song", + "duration": 1840, + "artist": "emamouse", + "genre": "Folk and Indie", + "secret": true, + "lobby": false, + "jukebox": true + }, + { + "url": "https://files.catbox.moe/6m88w6.mp3", + "title": "King Sucklet", + "duration": 1370, + "artist": "emamouse", + "genre": "Folk and Indie", + "secret": true, + "lobby": false, + "jukebox": true + } ] diff --git a/docker-compose.yml b/docker-compose.yml index b22b1c4ac0c..d9e9b3a7fd1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3' +version: "3" services: # Virgo DM server @@ -8,24 +8,24 @@ services: build: context: . dockerfile: Dockerfile - ports: + ports: - "2303:2303" depends_on: - db volumes: - ./config/:/vorestation/config - gamedata:/vorestation/data - # MariaDB/MySQL database: game + # MariaDB/MySQL database: game # (if you don't really need this, feel free to remove this section.) db: image: mariadb restart: unless-stopped env_file: - ./config/docker/mysql.env - volumes: - - ./SQL/tgstation_schema.sql:/docker-entrypoint-initdb.d/tgstation_schema.sql:ro - - ./SQL/feedback_schema.sql:/docker-entrypoint-initdb.d/feedback_schema.sql:ro - - database:/var/lib/mysql + volumes: + - ./SQL/tgstation_schema.sql:/docker-entrypoint-initdb.d/tgstation_schema.sql:ro + - ./SQL/feedback_schema.sql:/docker-entrypoint-initdb.d/feedback_schema.sql:ro + - database:/var/lib/mysql # Adminer, for managing the DB, commented out by default but uncomment if you need it I guess. #adminer: # image: wodby/adminer diff --git a/guides/Guide to Dream Maker.md b/guides/Guide to Dream Maker.md index e281f996ff4..c3d45e921ef 100644 --- a/guides/Guide to Dream Maker.md +++ b/guides/Guide to Dream Maker.md @@ -14,7 +14,7 @@ Choose “Open” You will be greeted with: https://i.imgur.com/oAbOjwR.png -If you’d prefer to skip right to codestuff/the wiki, this is a good start. Otherwise, continue below: +If you’d prefer to skip right to codestuff/the wiki, this is a good start. Otherwise, continue below: https://wiki.vore-station.net/Basics_of_Coding_in_BYOND MAPPERS: @@ -24,7 +24,7 @@ Tether is located in /maps/tether/, and each level of the station is Tether 01-0 Submaps are in the /submaps/ folder, and, for instance, if you are looking to add new submaps to the Underdark, you’ll expand underdark_pois and create a new .dmm in the folder by clicking on it, and then going to New. Example here: https://i.imgur.com/Q1Cqfll.png -If you are adding a submap, ensure you add it to _templates.dm, a small snippet is here: +If you are adding a submap, ensure you add it to \_templates.dm, a small snippet is here: https://i.imgur.com/Ek9jaCe.png Cost is how much the POI system has to spend to spawn that .dmm, and name/mappath are self-explanatory. @@ -34,7 +34,7 @@ Regarding new submaps, refer to Guide to Map Folders.md! If you have questions, ask in Discord in #dev-general! <3 SPRITERS: -If you are looking to edit icons, skip that, and just go to “icons” (expand it by hitting the +), and then find the icon file you’re looking for. Most people go to adding new drinks + foods for their first foray into DM, so: +If you are looking to edit icons, skip that, and just go to “icons” (expand it by hitting the +), and then find the icon file you’re looking for. Most people go to adding new drinks + foods for their first foray into DM, so: If you want to add a new drink, VOREStation-specific drinks are in icons/obj/drinks_vr.dmi, and VOREStation-specific food is icons/obj/food_vr.dmi. If you have questions, ask in Discord in #dev-general! <3 @@ -45,4 +45,4 @@ Refer to the pins in #dev-general for Visual Studio Code, but you can still code Coding is fairly self-explanatory, find the things you want to change and change it. There’s no robust tutorial to coding, but we have a coding tutorial of sorts and explanation on our wiki: https://wiki.vore-station.net/Basics_of_Coding_in_BYOND -As with spriters/mappers, if you have questions, ask in Discord in #dev-general! <3 \ No newline at end of file +As with spriters/mappers, if you have questions, ask in Discord in #dev-general! <3 diff --git a/guides/Guide to Map Folders.md b/guides/Guide to Map Folders.md index b7a1f81cf7f..71cf91593ff 100644 --- a/guides/Guide to Map Folders.md +++ b/guides/Guide to Map Folders.md @@ -3,24 +3,27 @@ As of 8/25/2020, the map folders have been reworked to allow expedition areas an This does introduce some changes, and I'll walk you through adding a NEW expedition area in the new system. ## EXPEDITION AREAS: + In order to add a new expedition area, we need to go to maps/expedition_vr and create a new folder. This will house our expedition map, as well as any map-specific code, and our submap pointing. In order to 'point' an expedition area to load a submap, you will need to ensure the following: -#include "../../submaps/pois_vr/expedition_area_name/_template_name.dm" +#include "../../submaps/pois_vr/expedition_area_name/\_template_name.dm" -This tells us "go to root, maps, submaps, pois_vr, mapname, and use _template_name.dm" +This tells us "go to root, maps, submaps, pois_vr, mapname, and use \_template_name.dm" Then simply place your poi's in the expedition_area_name folder as you would with any other POI. Easy way to do it is to look at the others. ## GATEWAY MAPS: + In order to add a new gateway area, we need to go to maps/gateway_vr and create a new .dm and .dmm for our map. Follow one of the existing gateway maps to configure your new map. DO NOT USE GATEWAY_ARCHIVE_VR as that is outdated/broken gateway maps. ## Folders listed as follows: + ~map_system: Polaris, do not touch example: Polaris, do not touch expedition_vr: VORE, our expedition areas (shared between station maps) @@ -32,13 +35,14 @@ overmap: Do not touch, ask maintainers. plane: Polaris, do not touch RandomZLevels: Polaris, do not touch southern_cross: Polaris, do not touch -submaps: All our submaps. non _vr files are Polaris, do not touch them. +submaps: All our submaps. non \_vr files are Polaris, do not touch them. tether: VORE, Our map, self-explanatory virgo_minitest: VORE, Testing map used for CI, do not touch -## What _submaps.dm (map-folder-specific, Tether uses _tether_submaps.dm) should look like: +## What \_submaps.dm (map-folder-specific, Tether uses \_tether_submaps.dm) should look like: # Map-specific areas should be loaded without a #include, and the mappath should just be: + mappath = "maps/your_map/tether_plains.dmm" # Non-map specific expedition areas should be loaded as follows: @@ -55,14 +59,14 @@ mappath = "maps/your_map/tether_plains.dmm" #include "../../expedition_vr/space/guttersite.dmm" #endif -#include "../../expedition_vr/beach/_beach.dm" +#include "../../expedition_vr/beach/\_beach.dm" /datum/map_template/tether_lateload/away_beach - name = "Desert Planet - Z1 Beach" - desc = "The beach away mission." - mappath = "maps/expedition_vr/beach/beach.dmm" - associated_map_datum = /datum/map_z_level/tether_lateload/away_beach +name = "Desert Planet - Z1 Beach" +desc = "The beach away mission." +mappath = "maps/expedition_vr/beach/beach.dmm" +associated_map_datum = /datum/map_z_level/tether_lateload/away_beach /datum/map_z_level/tether_lateload/away_beach - name = "Away Mission - Desert Beach" - z = Z_LEVEL_BEACH - base_turf = /turf/simulated/floor/outdoors/rocks/caves +name = "Away Mission - Desert Beach" +z = Z_LEVEL_BEACH +base_turf = /turf/simulated/floor/outdoors/rocks/caves diff --git a/guides/Guide to Opening Your First PR.md b/guides/Guide to Opening Your First PR.md index 4449bc684eb..d41131f18c3 100644 --- a/guides/Guide to Opening Your First PR.md +++ b/guides/Guide to Opening Your First PR.md @@ -28,8 +28,6 @@ Choose “Clone a Repo”, and then choose Github.com. You can then choose where https://i.imgur.com/y15Qir2.png https://i.imgur.com/bsw8p18.png - - Opening your Repo for the first time: Once your repo is cloned, you’ll be greeted with a screen SIMILAR to this (Note that mine has a lot of branches and repos): https://i.imgur.com/Ei6QZOh.png @@ -82,9 +80,9 @@ If the TO repo doesn’t autofill, don’t panic. Just choose VOREStation/VORESt Then type the NAME of your PR, and a description underneath, then hit “Create Pull Request”! -And that’s it! +And that’s it! -**You’ve now successfully made your first PR!** +**You’ve now successfully made your first PR!** Any further issues or changes, maintainers will assist you with! If you have any questions or run into any snags during this tutorial, feel free to @ a maintainer (The blue names on the sidebar) in #dev-general or just ask for help and someone should be with you momentarily! diff --git a/guides/Guide to Your First POI Map.md b/guides/Guide to Your First POI Map.md index 759ef042563..61e4d64f6e9 100644 --- a/guides/Guide to Your First POI Map.md +++ b/guides/Guide to Your First POI Map.md @@ -1,12 +1,12 @@ Welcome! -This guide **ASSUMES** you have gone through the Guide to Opening your First PR. If you have NOT done so yet, please refer here, and ask in Discord's #ss13-development channel (For CHOMPStation), #dev-general (for VOREStation), or #code (for Polaris) if you have any questions, or need assistance with completing these steps. +This guide **ASSUMES** you have gone through the Guide to Opening your First PR. If you have NOT done so yet, please refer here, and ask in Discord's #ss13-development channel (For CHOMPStation), #dev-general (for VOREStation), or #code (for Polaris) if you have any questions, or need assistance with completing these steps. You can also @ maintainers or staff devs, which can be viewed in the sidebar of each codebase’s Discord, and will usually have roles such as “Maintainer” (For VOREStation), “StaffDev/StaffMaintainer” (for CHOMPStation), and “Maintainer” (for Polaris). -[CHOMPStation]([https://github.com/CHOMPStation2/CHOMPStation2/blob/master/guides/Guide%20to%20Opening%20Your%20First%20PR.md](https://github.com/CHOMPStation2/CHOMPStation2/blob/master/guides/Guide%20to%20Opening%20Your%20First%20PR.md)) +[CHOMPStation](<[https://github.com/CHOMPStation2/CHOMPStation2/blob/master/guides/Guide%20to%20Opening%20Your%20First%20PR.md](https://github.com/CHOMPStation2/CHOMPStation2/blob/master/guides/Guide%20to%20Opening%20Your%20First%20PR.md)>) -[VOREStation]([https://github.com/VOREStation/VOREStation/blob/master/guides/Guide%20to%20Opening%20Your%20First%20PR.md](https://github.com/VOREStation/VOREStation/blob/master/guides/Guide%20to%20Opening%20Your%20First%20PR.md)) +[VOREStation](<[https://github.com/VOREStation/VOREStation/blob/master/guides/Guide%20to%20Opening%20Your%20First%20PR.md](https://github.com/VOREStation/VOREStation/blob/master/guides/Guide%20to%20Opening%20Your%20First%20PR.md)>) [Polaris - TBD] @@ -17,12 +17,12 @@ Before proceeding, remember to make your branch! We should have a new branch tit With that out of the way, congrats on getting setup! Let’s dive into how to make your first POI. \ \ To start, we need to open up the repo you downloaded earlier. If you’re not sure where that is, Gitkraken should be able to tell you by hovering over the codebase name, in the top left, and hitting **Alt+O** will open the file manager. \ -Either way, we should see [this]([https://i.imgur.com/FOUVK4n.png](https://i.imgur.com/FOUVK4n.png)) - Image references CHOMPStation, but the general folders should be the same for Polaris + VOREStation. +Either way, we should see [this](<[https://i.imgur.com/FOUVK4n.png](https://i.imgur.com/FOUVK4n.png)>) - Image references CHOMPStation, but the general folders should be the same for Polaris + VOREStation. Before we can map, we need to setup several code prerequisites in order to actually have a new area for our map. In order to do so, we are going to locate the POI folder. We are going to add a POI to the Wilderness area for our tutorial. Follow this reference: \ -Go to /maps/, and then find the folder the POIs for the given map are saved. This is code-base specific, so Polaris + CHOMP use /maps/submaps/surface_submaps/ for theirs, and then each folder (mountains, wilderness, plains) is a different area. If you’re on Southern Cross, Plains is the area around the outpost, Mountains is the mines, and Wilderness is the deep wilds. Polaris, TBD. +Go to /maps/, and then find the folder the POIs for the given map are saved. This is code-base specific, so Polaris + CHOMP use /maps/submaps/surface_submaps/ for theirs, and then each folder (mountains, wilderness, plains) is a different area. If you’re on Southern Cross, Plains is the area around the outpost, Mountains is the mines, and Wilderness is the deep wilds. Polaris, TBD. VORE has their submaps for SPECIFIC areas defined in /mapused (IE Tether)/submaps. This sub-main folder should only be used for map-specific POIs, for example, POIs that would only exist if Tether was loaded. @@ -56,8 +56,8 @@ With that, we save, and exit the code. We’ll come back to it at a later step t For this next step, return to the BASE folder, where the .dme and maps/etc folders are. - \ -We’re going to navigate to *tools* and then StrongDMM. This is not REQUIRED, but is heavily recommended - maintainers will ask you to run mapmerge where possible if you use DreamMaker. The rest of this guide WILL ASSUME YOU ARE USING STRONGDMM. The wiki will offer sections for DreamMaker as well as StrongDMM. \ +\ +We’re going to navigate to _tools_ and then StrongDMM. This is not REQUIRED, but is heavily recommended - maintainers will ask you to run mapmerge where possible if you use DreamMaker. The rest of this guide WILL ASSUME YOU ARE USING STRONGDMM. The wiki will offer sections for DreamMaker as well as StrongDMM. \ \ Run sdmmlauncher.exe. Screenshot here: \ [https://i.imgur.com/VxvRntf.png](https://i.imgur.com/VxvRntf.png) @@ -77,7 +77,7 @@ You should also be able to see the name in the top left. Now, we are going to go to File, New Map. \ This will open a dialogue box with the base folder of our repo. Don’t panic. \ -Go to /maps/, and then find the folder the POIs for the given map are saved. This is code-base specific, so Polaris + CHOMP use /maps/submaps/surface_submaps/ for theirs, and then each folder (mountains, wilderness, plains) is a different area. If you’re on Southern Cross, Plains is the area around the outpost, Mountains is the mines, and Wilderness is the deep wilds. Polaris, TBD. +Go to /maps/, and then find the folder the POIs for the given map are saved. This is code-base specific, so Polaris + CHOMP use /maps/submaps/surface_submaps/ for theirs, and then each folder (mountains, wilderness, plains) is a different area. If you’re on Southern Cross, Plains is the area around the outpost, Mountains is the mines, and Wilderness is the deep wilds. Polaris, TBD. VORE has their submaps for SPECIFIC areas defined in /mapused (IE Tether)/submaps. This sub-main folder should only be used for map-specific POIs, for example, POIs that would only exist if Tether was loaded. @@ -92,7 +92,7 @@ Hit Ok. \ \ Your new map will load in the bottom-left corner, depending on SDMM. Scroll in using your mouse, and hold the middle mouse button (or whatever the hotkey is if SDMM ever changes) to pan. -Once we’ve navigated and zoomed so our POI is relatively sized, we should see this: [https://i.imgur.com/e8VhPxk.png](https://i.imgur.com/e8VhPxk.png) +Once we’ve navigated and zoomed so our POI is relatively sized, we should see this: [https://i.imgur.com/e8VhPxk.png](https://i.imgur.com/e8VhPxk.png) Hit Save (Ctrl + S) now! Just in case. @@ -152,4 +152,4 @@ Commit, and then again, as per prior, we are going to start a pull request. At t As with the other guides, if you run into issues, please let maintainers know and we’ll help you out. DON’T FEEL BAD FOR BEING NEW AND GOING “AAA”. \ \ -We all started somewhere. I hope this guide helps give you the confidence you need to contribute to this codebase and help keep our project going. Thank you for your time and effort. <3 \ No newline at end of file +We all started somewhere. I hope this guide helps give you the confidence you need to contribute to this codebase and help keep our project going. Thank you for your time and effort. <3 diff --git a/guides/Overmap Ships and Places - What's Needed.md b/guides/Overmap Ships and Places - What's Needed.md index f5795f0cbfd..76205ed86a2 100644 --- a/guides/Overmap Ships and Places - What's Needed.md +++ b/guides/Overmap Ships and Places - What's Needed.md @@ -4,6 +4,7 @@ Proper, full-length guide will be added later to here + the wiki. For now, just use this as reference for what is needed for Overmap ships + locations. **CREATED IN-EDITOR:** + ``` /obj/effect/shuttle_landmark var edits: @@ -14,13 +15,14 @@ For now, just use this as reference for what is needed for Overmap ships + locat ``` **CREATED IN-CODE:** + ```c /area/shuttle/SHIPNAME name = "\improper [Name]" // Just replace [Name] with whatever your want to name the ship icon_state = "shuttlered" - requires_power = 1 // Or 0 if you don't want to have to power the ship yourself. + requires_power = 1 // Or 0 if you don't want to have to power the ship yourself. //Area should probably be placed in southern-cross-areas.dm but the rest can go into some file all together. - + /datum/shuttle/autodock/overmap/SHIPNAME name = "[Name]" warmup_time = 0 @@ -44,6 +46,7 @@ For now, just use this as reference for what is needed for Overmap ships + locat **OVERMAP SHIP CREATION INSTRUCTIONS:** Build your shuttle however you'd like, though it MUST have: + - Phoron cannister(s) hooked up to proper engines. /obj/machinery/atmospherics/unary/engine - Engine Control. `/obj/machinery/computer/ship/engines` - Helm Control. `/obj/machinery/computer/ship/helm` @@ -54,6 +57,7 @@ Build your shuttle however you'd like, though it MUST have: - The shuttle also needs to be placed entirely in the designated area that you made in the above code, since shuttles are based off of the area everything is in. It would be **RECOMMENDED** to also have: + - Sensors, controlled by `/obj/machinery/computer/ship/sensors` and `/obj/machinery/shipsensors` (maybe the /weak variant for small ships if you add them at all?) - Docking Controller. Not 100% sure on how these work yet, but will be updated as needed. Not necessary, just nice to have for ease of access. -- A pump somewhere in the fuel intake to your engines, for better fuel management. \ No newline at end of file +- A pump somewhere in the fuel intake to your engines, for better fuel management. diff --git a/guides/VSCode Setup Guide.md b/guides/VSCode Setup Guide.md index 35f298b3c25..39d14d4593e 100644 --- a/guides/VSCode Setup Guide.md +++ b/guides/VSCode Setup Guide.md @@ -27,4 +27,4 @@ If you run into issues, ask in Discord for help. **Quick Tips for VSCode** Highlighting a proc and right clicking, then going to "Definition" or "Implementation" will allow you to easily see/lookup wherever it's used. This is massively helpful over having to manually search it. CTRL+F will bring up a search, that also allows a replace line-by-line. -CTRL+Clicking will also (usually) take you to the definition of a proc/verb/etc. \ No newline at end of file +CTRL+Clicking will also (usually) take you to the definition of a proc/verb/etc. diff --git a/html/admin/search.js b/html/admin/search.js index 639a3729fe3..b51c3b20dcf 100644 --- a/html/admin/search.js +++ b/html/admin/search.js @@ -1,33 +1,34 @@ -function selectTextField(){ - var filter_text = document.getElementById('filter'); - filter_text.focus(); - filter_text.select(); +function selectTextField() { + var filter_text = document.getElementById("filter"); + filter_text.focus(); + filter_text.select(); } -function updateSearch(){ - var input_form = document.getElementById('filter'); - var filter = input_form.value.toLowerCase(); - input_form.value = filter; - var table = document.getElementById('searchable'); - var alt_style = 'norm'; - for(var i = 0; i < table.rows.length; i++){ - try{ - var row = table.rows[i]; - if(row.className == 'title') continue; - var found=0; - for(var j = 0; j < row.cells.length; j++){ - var cell = row.cells[j]; - if(cell.innerText.toLowerCase().indexOf(filter) != -1){ - found=1; - break; - } - } - if(found == 0) row.style.display='none'; - else{ - row.style.display='table-row'; /* DON'T make tables with block property */ - row.className = alt_style; - if(alt_style == 'alt') alt_style = 'norm'; - else alt_style = 'alt'; - } - }catch(err) { } - } +function updateSearch() { + var input_form = document.getElementById("filter"); + var filter = input_form.value.toLowerCase(); + input_form.value = filter; + var table = document.getElementById("searchable"); + var alt_style = "norm"; + for (var i = 0; i < table.rows.length; i++) { + try { + var row = table.rows[i]; + if (row.className == "title") continue; + var found = 0; + for (var j = 0; j < row.cells.length; j++) { + var cell = row.cells[j]; + if (cell.innerText.toLowerCase().indexOf(filter) != -1) { + found = 1; + break; + } + } + if (found == 0) row.style.display = "none"; + else { + row.style.display = + "table-row"; /* DON'T make tables with block property */ + row.className = alt_style; + if (alt_style == "alt") alt_style = "norm"; + else alt_style = "alt"; + } + } catch (err) {} + } } diff --git a/html/admin/view_variables.css b/html/admin/view_variables.css index 09923e30af4..5d9a582e790 100644 --- a/html/admin/view_variables.css +++ b/html/admin/view_variables.css @@ -1,236 +1,233 @@ body { - font-family: Verdana, sans-serif; - font-size: 9pt; + font-family: Verdana, sans-serif; + font-size: 9pt; } .bold { - font-weight: bold; + font-weight: bold; } .italic, .italics { - font-style: italic; + font-style: italic; } .underline { - text-decoration: underline; + text-decoration: underline; } .value { - font-family: "Courier New", monospace; - font-size: 8pt; - display: inline-block; + font-family: "Courier New", monospace; + font-size: 8pt; + display: inline-block; } table.matrix { - border-collapse: collapse; border-spacing: 0; - font-size: 7pt; + border-collapse: collapse; + border-spacing: 0; + font-size: 7pt; } -.matrix td{ - text-align: center; - padding: 0 1ex 0ex 1ex; +.matrix td { + text-align: center; + padding: 0 1ex 0ex 1ex; } table.matrixbrak { - border-collapse: collapse; border-spacing: 0; + border-collapse: collapse; + border-spacing: 0; } table.matrixbrak td.lbrak { - width: 0.8ex; - font-size: 50%; - border-top: solid 0.25ex black; - border-bottom: solid 0.25ex black; - border-left: solid 0.5ex black; - border-right: none; + width: 0.8ex; + font-size: 50%; + border-top: solid 0.25ex black; + border-bottom: solid 0.25ex black; + border-left: solid 0.5ex black; + border-right: none; } table.matrixbrak td.rbrak { - width: 0.8ex; - font-size: 50%; - border-top: solid 0.25ex black; - border-bottom: solid 0.25ex black; - border-right: solid 0.5ex black; - border-left: none; + width: 0.8ex; + font-size: 50%; + border-top: solid 0.25ex black; + border-bottom: solid 0.25ex black; + border-right: solid 0.5ex black; + border-left: none; } .green { - color: hsl(133, 100%, 51%); + color: hsl(133, 100%, 51%); } .darkgreen { - color: hsl(120, 100%, 25%); + color: hsl(120, 100%, 25%); } .grey { - color: hsl(0, 0%, 51%); + color: hsl(0, 0%, 51%); } .red { - color: hsl(0, 100%, 50%); + color: hsl(0, 100%, 50%); } .crimson { - color: hsl(348, 83%, 47%); + color: hsl(348, 83%, 47%); } .maroon { - color: hsl(0, 100%, 25%); + color: hsl(0, 100%, 25%); } .brown { - color: hsl(21, 58%, 35%); + color: hsl(21, 58%, 35%); } .blue { - color: hsl(240, 100%, 50%); + color: hsl(240, 100%, 50%); } .black { - color: hsl(0, 0%, 0%); + color: hsl(0, 0%, 0%); } .white { - color: hsl(0, 0%, 0%); + color: hsl(0, 0%, 0%); } .darkgray { - color: hsl(0, 0%, 50%); + color: hsl(0, 0%, 50%); } .gray { - color: hsl(0, 0%, 66%); + color: hsl(0, 0%, 66%); } .yellow { - color: hsl(48, 100%, 50%); + color: hsl(48, 100%, 50%); } .pink { - color: hsl(350, 100%, 88%); + color: hsl(350, 100%, 88%); } .cyan { - color: hsl(180, 100%, 50%); + color: hsl(180, 100%, 50%); } .orange { - color: hsl(33, 100%, 50%); + color: hsl(33, 100%, 50%); } .nicegreen { - color: hsl(133, 79%, 37%); + color: hsl(133, 79%, 37%); } -.brute -{ - color: #FF3333; +.brute { + color: #ff3333; } -.burn -{ - color: #FF9933; +.burn { + color: #ff9933; } -.tox -{ - color: #00CC66; +.tox { + color: #00cc66; } -.oxy -{ - color: #0053FA; +.oxy { + color: #0053fa; } -.clone -{ - color: #00CCCC; +.clone { + color: #00cccc; } /* Dark Mode */ .dark body { - background-color: #131313; - color: #f0f6fc; + background-color: #131313; + color: #f0f6fc; } .dark a { - color: rgb(68, 147, 248); + color: rgb(68, 147, 248); } .dark select { - background-color: black; - color: white; + background-color: black; + color: white; } .dark input { - background-color: black; - color: white; + background-color: black; + color: white; } .dark .green { - color: hsl(133, 93%, 30%); + color: hsl(133, 93%, 30%); } .dark .darkgreen { - color: hsl(120, 100%, 25%); + color: hsl(120, 100%, 25%); } .dark .grey { - color: hsl(0, 0%, 51%); + color: hsl(0, 0%, 51%); } .dark .red { - color: hsl(0, 100%, 50%); + color: hsl(0, 100%, 50%); } .dark .crimson { - color: hsl(348, 83%, 47%); + color: hsl(348, 83%, 47%); } .dark .maroon { - color: hsl(0, 100%, 39%); + color: hsl(0, 100%, 39%); } .dark .brown { - color: hsl(21, 69%, 55%); + color: hsl(21, 69%, 55%); } .dark .blue { - color: hsl(224, 98%, 62%); + color: hsl(224, 98%, 62%); } .dark .black { - color: hsl(0, 0%, 100%); + color: hsl(0, 0%, 100%); } .dark .white { - color: hsl(0, 0%, 100%); + color: hsl(0, 0%, 100%); } .dark .darkgray { - color: hsl(0, 0%, 50%); + color: hsl(0, 0%, 50%); } .dark .gray { - color: hsl(0, 0%, 66%); + color: hsl(0, 0%, 66%); } .dark .yellow { - color: hsl(48, 100%, 50%); + color: hsl(48, 100%, 50%); } .dark .pink { - color: hsl(350, 100%, 88%); + color: hsl(350, 100%, 88%); } .dark .cyan { - color: hsl(180, 100%, 50%); + color: hsl(180, 100%, 50%); } .dark .orange { - color: hsl(33, 100%, 50%); + color: hsl(33, 100%, 50%); } .dark .nicegreen { - color: hsl(133, 93%, 30%); + color: hsl(133, 93%, 30%); } diff --git a/html/archivedchangelog.html b/html/archivedchangelog.html index cbd6206420b..b4037ca96bf 100644 --- a/html/archivedchangelog.html +++ b/html/archivedchangelog.html @@ -3,968 +3,1823 @@ Stick old posts here to prevent cluttering of main changelog. -->
-

December 28nd

-

Cael_Aislinn updated:

- -
- -
-

November 2012 - January 2013

-

chinsky updated:

- -

CIB updated:

- -

CaelAislinn updated:

- -

Ravensdale updated:

- -
- -
-

December 3rd

-

Cael_Aislinn updated:

- +

December 28nd

+

Cael_Aislinn updated:

+ +
+ +
+

November 2012 - January 2013

+

chinsky updated:

+ +

CIB updated:

+ +

CaelAislinn updated:

+ +

Ravensdale updated:

+ +
+ +
+

December 3rd

+

Cael_Aislinn updated:

+ +
+ +
+

23.11.12

+

CIB updated:

+ +
+ +
+

14.11.12

+

Chinsky updated:

+ +

CIB updated:

+ +
+ +
+

November 12th

+

CIB updated:

+ +
+ +
+

November 11th

+

CIB updated:

+ +
+ +
+

November 9th

+

AterIgnis updated:

+ +
+ +
+

6.11.2012

+

Chinsky updated:

+ +
+ +
+

November 4th

+

SkyMarshal updated:

+ +
+ +
+

October 24th

+

Mij updated:

+ +
+ +
+

October 22nd

+

Cael_Aislinn updated:

+ +
+ +
+

October 18th

+

CIB updated:

+ +

Chinsky updated:

+ +
+ +
+

17.10.2012

+

CIB updated:

+ +

Chinsky updated:

+ +
+ +
+

October 13th, 2012

+

Cael_Aislinn updated:

+ +

CIB updated:

+ +
+ +
+

October 12th, 2012

+

Cael_Aislinn updated:

+ +
+ +
+

October 9th, 2012

+

Cael_Aislinn updated:

+ +
+ +
+

September 26th, 2012

+

Cael_Aislinn updated:

+ +
+ +
+

September 24th, 2012

+

Cael_Aislinn updated:

+ +
+ +
+

September 23nd, 2012

+

Cael_Aislinn updated:

+ +
+ +
+

August 22, 2012

+

Cael_Aislinn updated:

+ +
+ +
+

15th August 2012

+

Cael_Aislinn updated:

+ +
+ +
+

7th August 2012

+

CIB updated:

+ +
+ +
+

4 August 2012

+

Cael_Aislinn updated:

+ + +

FireFishie updated:

+ +
+ +
+

2 August 2012

+

Cael_Aislinn updated:

+ +
+ +
+

10 July 2012

+

Abi79 updated:

+ + +

CIB updated:

+ +
+ +
+

9 July 2012

+

CIB updated:

+ +
+ +
+

5 July 2012

+

Cael_Aislinn updated:

+ +
+ +
+

3 July 2012

+

CIB updated:

+ +
+ +
+

29 June 2012

+

Erthilo updated:

+ +
+
+

28 June 2012

+

Chinsky updated:

+ +
+
+

27 June 2012

+

Erthilo updated:

+ +
+
+

26 June 2012

+

TG updated:

+ +
+ +
+

25 June 2012

+

Erthilo updated:

+ +

Watermelon Storm updated:

+ +

Drieden updated:

+ +
+ +
+

23 June 2012

+

SkyMarshal updated:

+ +

TG updated:

+ +
+ +
+

22 June 2012

+

Cael_Aislinn updated:

+ +
+ +
+

18 June 2012

+

Cael_Aislinn updated:

+ +
+ +
+

16 June 2012

+

Cael_Aislinn updated:

+ +
+ +
+

09 June 2012

+

Erthilo updated:

+ +
+ +
+

07 June 2012

+

SkyMarshal updated:

+ +
+ +
+

06 June 2012

+

Erthilo updated:

+ +
+ +
+

04 June 2012

+

TG updated:

+ +

SkyMarshal updated:

+ +

Erthilo updated:

+ +
+ +
+

01 June 2012

+

Erthilo updated:

+ +
+ +
+

29 May 2012

+

Aryn updated:

+ +
+ +
+

28 May 2012

+

Erthilo updated:

+ +
+ +
+

27 May 2012

+

Abi79 updated:

+ +

Erthilo updated:

+ +
+ +
+

26 May 2012

+

Erthilo updated:

+ + +

Abi79 updated:

+ +
+ +
+

25 May 2012

+

Erthilo updated:

+ +
+ +
+

24 May 2012

+

cib updated:

+ +
+ +
+

23 May 2012

+

CIB updated:

+ +

TG & Erthilo updated:

+ +
+ +
+

22 May 2012

+

cib updated:

+ +

Erthilo updated:

+ +
+ +
+

21 May 2012

+

TG updated:

+ +

SkyMarshal updated:

+ +

Uristqwerty updated:

+ +

Erthilo updated:

+ +
+ +
+

20 May 2012

+

Erthilo updated:

+ +
+ +
+

19 May 2012

+

cib updated:

+ +

TG updated:

+ +
+ +
+

17 May 2012

+

TG updated:

+ +

Erthilo updated:

+ +

Abi79 updated:

+ +

SkyMarshal updated:

+ +
+ +
+

16 May 2012

+

Erthilo updated:

+ +
+ +
+

15 May 2012

+

TG updated:

+ +

Erthilo updated:

+ +
+ +
+

13 May 2012

+

TG updated:

+ +
+ +
+

10 May 2012

+

Erthilo updated:

+ +

TG updated:

+ +
+ +
+

07 May 2012

+

TG updated:

+ +
+ +
+

06 May 2012

+

TG updated:

+ +
+ +
+

05 May 2012

+

Erthilo updated:

+ +
+ +
+

04 May 2012

+

dopeghoti updated:

+ +
+ +
+

03 May 2012

+

TG updated:

+ +
+ +
+

2nd May 2012

+

TG updated:

+ +

Erthilo updated:

+ +
+ +
+

1st May 2012

+

Mloc updated:

+ +

Erthilo updated:

+ +
+ +
+

30th April 2012

+

Mloc updated:

+ +

Erthilo updated:

+ +

TG updated:

+ +
+ +
+

TG

+

29th April 2012 updated:

+
- -
-

23.11.12

-

CIB updated:

- -
- -
-

14.11.12

-

Chinsky updated:

- -

CIB updated:

- -
- -
-

November 12th

-

CIB updated:

- -
- -
-

November 11th

-

CIB updated:

- -
- -
-

November 9th

-

AterIgnis updated:

- -
- -
-

6.11.2012

-

Chinsky updated:

- -
- -
-

November 4th

-

SkyMarshal updated:

- -
- -
-

October 24th

-

Mij updated:

- -
- -
-

October 22nd

-

Cael_Aislinn updated:

- -
- -
-

October 18th

-

CIB updated:

- -

Chinsky updated:

- -
- -
-

17.10.2012

-

CIB updated:

- -

Chinsky updated:

- -
- -
-

October 13th, 2012

-

Cael_Aislinn updated:

- -

CIB updated:

- -
- -
-

October 12th, 2012

-

Cael_Aislinn updated:

- -
- -
-

October 9th, 2012

-

Cael_Aislinn updated:

- -
- -
-

September 26th, 2012

-

Cael_Aislinn updated:

- -
- -
-

September 24th, 2012

-

Cael_Aislinn updated:

- -
- -
-

September 23nd, 2012

-

Cael_Aislinn updated:

- -
- -
-

August 22, 2012

-

Cael_Aislinn updated:

- -
- -
-

15th August 2012

-

Cael_Aislinn updated:

- -
- -
-

7th August 2012

-

CIB updated:

- -
- -
-

4 August 2012

-

Cael_Aislinn updated:

- - -

FireFishie updated:

- -
- -
-

2 August 2012

-

Cael_Aislinn updated:

- -
- -
-

10 July 2012

-

Abi79 updated:

- - -

CIB updated:

- -
- -
-

9 July 2012

-

CIB updated:

- -
- -
-

5 July 2012

-

Cael_Aislinn updated:

- -
- -
-

3 July 2012

-

CIB updated:

- -
- -
-

29 June 2012

-

Erthilo updated:

- -
-
-

28 June 2012

-

Chinsky updated:

- -
-
-

27 June 2012

-

Erthilo updated:

- -
-
-

26 June 2012

-

TG updated:

- -
- -
-

25 June 2012

-

Erthilo updated:

- -

Watermelon Storm updated:

- -

Drieden updated:

- -
- -
-

23 June 2012

-

SkyMarshal updated:

- -

TG updated:

- -
- -
-

22 June 2012

-

Cael_Aislinn updated:

- -
- -
-

18 June 2012

-

Cael_Aislinn updated:

- -
- -
-

16 June 2012

-

Cael_Aislinn updated:

- -
- -
-

09 June 2012

-

Erthilo updated:

- -
- -
-

07 June 2012

-

SkyMarshal updated:

- -
- -
-

06 June 2012

-

Erthilo updated:

- -
- -
-

04 June 2012

-

TG updated:

- -

SkyMarshal updated:

- -

Erthilo updated:

- -
- -
-

01 June 2012

-

Erthilo updated:

- -
- -
-

29 May 2012

-

Aryn updated:

- -
- -
-

28 May 2012

-

Erthilo updated:

- -
- -
-

27 May 2012

-

Abi79 updated:

- -

Erthilo updated:

- -
- -
-

26 May 2012

-

Erthilo updated:

- - -

Abi79 updated:

- -
- -
-

25 May 2012

-

Erthilo updated:

- -
- -
-

24 May 2012

-

cib updated:

- -
- -
-

23 May 2012

-

CIB updated:

- -

TG & Erthilo updated:

- -
- -
-

22 May 2012

-

cib updated:

- -

Erthilo updated:

- -
- -
-

21 May 2012

-

TG updated:

- -

SkyMarshal updated:

- -

Uristqwerty updated:

- -

Erthilo updated:

- -
- -
-

20 May 2012

-

Erthilo updated:

- -
- -
-

19 May 2012

-

cib updated:

- -

TG updated:

- -
- -
-

17 May 2012

-

TG updated:

- -

Erthilo updated:

- -

Abi79 updated:

- -

SkyMarshal updated:

- -
- -
-

16 May 2012

-

Erthilo updated:

- -
- -
-

15 May 2012

-

TG updated:

- -

Erthilo updated:

- -
- -
-

13 May 2012

-

TG updated:

- -
- -
-

10 May 2012

-

Erthilo updated:

- -

TG updated:

- -
- -
-

07 May 2012

-

TG updated:

- -
- -
-

06 May 2012

-

TG updated:

- -
- -
-

05 May 2012

-

Erthilo updated:

- -
- -
-

04 May 2012

-

dopeghoti updated:

- -
- -
-

03 May 2012

-

TG updated:

- -
- -
-

2nd May 2012

-

TG updated:

- -

Erthilo updated:

- -
- -
-

1st May 2012

-

Mloc updated:

- -

Erthilo updated:

- -
- -
-

30th April 2012

-

Mloc updated:

- -

Erthilo updated:

- -

TG updated:

- -
- -
-

TG

-

29th April 2012 updated:

- -
\ No newline at end of file diff --git a/html/browser/codex.css b/html/browser/codex.css index c757b4fc0e8..969d43c2498 100644 --- a/html/browser/codex.css +++ b/html/browser/codex.css @@ -1,34 +1,30 @@ -body -{ - background-image: url("paper_bg.png"); +body { + background-image: url("paper_bg.png"); } -.button-group .button -{ - border: 1px solid RoyalBlue; - color: black; - padding: 5px 32px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; - cursor: pointer; - width: 40%; - display: block; +.button-group .button { + border: 1px solid RoyalBlue; + color: black; + padding: 5px 32px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + cursor: pointer; + width: 40%; } -.button-group .button:not(:last-child) -{ - border-bottom: none; /* Will hopefully prevent double borders */ +.button-group .button:not(:last-child) { + border-bottom: none; /* Will hopefully prevent double borders */ } -.button-group .button:hover -{ - background-color: RoyalBlue; - color: white; +.button-group .button:hover { + background-color: RoyalBlue; + color: white; } - -table, th, td { - border: 0px solid black; -} \ No newline at end of file +table, +th, +td { + border: 0px solid black; +} diff --git a/html/browser/common.css b/html/browser/common.css index 182ebed5273..101a5100692 100644 --- a/html/browser/common.css +++ b/html/browser/common.css @@ -187,33 +187,28 @@ h4 { color: #ff0000; } -.brute -{ - color: #FF3333; +.brute { + color: #ff3333; } -.burn -{ - color: #FF9933; +.burn { + color: #ff9933; } -.tox -{ - color: #00CC66; +.tox { + color: #00cc66; } -.oxy -{ - color: #0053FA; +.oxy { + color: #0053fa; } -.clone -{ - color: #00CCCC; +.clone { + color: #00cccc; } .highlight { - color: #8BA5C4; + color: #8ba5c4; } .dark { @@ -288,8 +283,8 @@ h4 { .boldnotice { position: relative; - background: #E9C183; - color: #15345A; + background: #e9c183; + color: #15345a; font-weight: bold; font-size: 10px; font-style: italic; @@ -462,31 +457,31 @@ div.notice { background-color: #b4b4b4; } -input:checked+.slider { +input:checked + .slider { background-color: #40628a; } -input:checked+.slider.red { +input:checked + .slider.red { background-color: #a92621; } -input:checked+.slider.locked { +input:checked + .slider.locked { background-color: #707070; } -input:focus+.slider { +input:focus + .slider { box-shadow: 0 0 1px #2196f3; } -input:focus+.slider.red { +input:focus + .slider.red { box-shadow: 0 0 1px #f3212d; } -input:focus+.slider.locked { +input:focus + .slider.locked { box-shadow: 0 0 1px #979797; } -input:checked+.slider:before { +input:checked + .slider:before { transform: translateX(24px); } diff --git a/html/browser/cryo.css b/html/browser/cryo.css index 05e9746aa25..82991e0b78f 100644 --- a/html/browser/cryo.css +++ b/html/browser/cryo.css @@ -1,11 +1,9 @@ -.statusLabel -{ - width: 128px; - float: left; - overflow: hidden; +.statusLabel { + width: 128px; + float: left; + overflow: hidden; } -.statusValue -{ - float: left; +.statusValue { + float: left; } diff --git a/html/browser/scannernew.css b/html/browser/scannernew.css index a2c404b2c56..d1cbbe9cec4 100644 --- a/html/browser/scannernew.css +++ b/html/browser/scannernew.css @@ -1,25 +1,20 @@ -.getblockstring -{ - font-family: Fixed, monospace; +.getblockstring { + font-family: Fixed, monospace; } -.blockString -{ - width: 55px; - height: 19px; - padding: 0 8px 8px 0; - float: left; +.blockString { + width: 55px; + height: 19px; + padding: 0 8px 8px 0; + float: left; } -.statusLabel -{ - width: 128px; - float: left; - overflow: hidden; +.statusLabel { + width: 128px; + float: left; + overflow: hidden; } -.statusValue -{ - float: left; +.statusValue { + float: left; } - diff --git a/html/browser/sleeper.css b/html/browser/sleeper.css index 05e9746aa25..82991e0b78f 100644 --- a/html/browser/sleeper.css +++ b/html/browser/sleeper.css @@ -1,11 +1,9 @@ -.statusLabel -{ - width: 128px; - float: left; - overflow: hidden; +.statusLabel { + width: 128px; + float: left; + overflow: hidden; } -.statusValue -{ - float: left; +.statusValue { + float: left; } diff --git a/html/changelog.css b/html/changelog.css index 69a3a16405e..c6dffdcf132 100644 --- a/html/changelog.css +++ b/html/changelog.css @@ -1,77 +1,119 @@ -body{font-family:Tahoma,sans-serif;} -.top{font-size:12px;} -a img {border:none;} -.bgimages16 li { - padding:2px 10px 2px 30px; - background-position:6px center; - background-repeat:no-repeat; - border:1px solid #ddd; - border-left:4px solid #999; - margin-bottom:2px; +body { + font-family: Tahoma, sans-serif; +} +.top { + font-size: 12px; +} +a img { + border: none; +} +.bgimages16 li { + padding: 2px 10px 2px 30px; + background-position: 6px center; + background-repeat: no-repeat; + border: 1px solid #ddd; + border-left: 4px solid #999; + margin-bottom: 2px; +} +.bugfix { + background-image: url(bug-minus.png); +} +.wip { + background-image: url(hard-hat-exclamation.png); +} +.tweak { + background-image: url(wrench-screwdriver.png); +} +.soundadd { + background-image: url(music-plus.png); +} +.sounddel { + background-image: url(music-minus.png); +} +.rscdel { + background-image: url(cross-circle.png); +} +.rscadd { + background-image: url(tick-circle.png); +} +.imageadd { + background-image: url(image-plus.png); +} +.imagedel { + background-image: url(image-minus.png); +} +.spellcheck { + background-image: url(spell-check.png); +} +.experiment { + background-image: url(burn-exclamation.png); +} +.maptweak { + background-image: url(map-pencil.png); +} +.sansserif { + font-size: 12px; } -.bugfix {background-image:url(bug-minus.png)} -.wip {background-image:url(hard-hat-exclamation.png)} -.tweak {background-image:url(wrench-screwdriver.png)} -.soundadd {background-image:url(music-plus.png)} -.sounddel {background-image:url(music-minus.png)} -.rscdel {background-image:url(cross-circle.png)} -.rscadd {background-image:url(tick-circle.png)} -.imageadd {background-image:url(image-plus.png)} -.imagedel {background-image:url(image-minus.png)} -.spellcheck {background-image:url(spell-check.png)} -.experiment {background-image:url(burn-exclamation.png)} -.maptweak {background-image:url(map-pencil.png)} -.sansserif {font-size:12px;} .commit { - margin-bottom:20px; - font-size:100%;font-weight:normal; + margin-bottom: 20px; + font-size: 100%; + font-weight: normal; } .changes { - list-style:none; - margin:5px 0; - padding:0 0 0 25px; - font-size:0.8em; + list-style: none; + margin: 5px 0; + padding: 0 0 0 25px; + font-size: 0.8em; } .date { - margin:10px 0; - color:blue; - border-bottom:2px solid #00f; - width:60%; - padding:2px 0; - font-size:1em; - font-weight:bold; -} -.author { - padding-left:10px; - margin:0; - font-weight:bold; - font-size:0.9em; - } -.drop { - cursor:pointer; - border:1px solid #999; - display:inline; - font-size:0.9em; - padding:1px 20px 1px 5px; - line-height:16px; + margin: 10px 0; + color: blue; + border-bottom: 2px solid #00f; + width: 60%; + padding: 2px 0; + font-size: 1em; + font-weight: bold; +} +.author { + padding-left: 10px; + margin: 0; + font-weight: bold; + font-size: 0.9em; +} +.drop { + cursor: pointer; + border: 1px solid #999; + display: inline; + font-size: 0.9em; + padding: 1px 20px 1px 5px; + line-height: 16px; +} +.hidden { + display: none; } -.hidden {display:none;} .indrop { - margin:2px 0 0 0; - clear:both; - background:#fff; - border:1px solid #ddd; - padding:5px 10px; - } + margin: 2px 0 0 0; + clear: both; + background: #fff; + border: 1px solid #ddd; + padding: 5px 10px; +} .indrop p { - margin:0; - font-size:0.8em; - line-height:16px; - margin:1px 0; + margin: 0; + font-size: 0.8em; + line-height: 16px; + margin: 1px 0; } .indrop img { - margin-right:5px; - vertical-align:middle;} -.closed {background:url(chevron-expand.png) right center no-repeat;} -.open {background:url(chevron.png) right center no-repeat;} -.lic {font-size:9px;} + margin-right: 5px; + vertical-align: middle; +} +.closed { + background: url(chevron-expand.png) right center no-repeat; +} +.open { + background: url(chevron.png) right center no-repeat; +} +.lic { + font-size: 9px; +} diff --git a/html/changelog.js b/html/changelog.js index 4146d0f094e..0da7e59cb12 100644 --- a/html/changelog.js +++ b/html/changelog.js @@ -55,33 +55,32 @@ function filterchanges(type){ } */ function dropdowns() { - var drops = $('div.drop'); - var indrops = $('div.indrop'); - if(drops.length!=indrops.length){ - alert("Some coder fucked up with dropdowns"); - } - drops.each(function(index){ - $(this).toggleClass('closed'); - $(indrops[index]).hide(); - $(this).click(function(){ - $(this).toggleClass('closed'); - $(this).toggleClass('open'); - $(indrops[index]).toggle(); - }); - }); + var drops = $("div.drop"); + var indrops = $("div.indrop"); + if (drops.length != indrops.length) { + alert("Some coder fucked up with dropdowns"); + } + drops.each(function (index) { + $(this).toggleClass("closed"); + $(indrops[index]).hide(); + $(this).click(function () { + $(this).toggleClass("closed"); + $(this).toggleClass("open"); + $(indrops[index]).toggle(); + }); + }); } -function filterchanges(type){ - $('ul.changes li').each(function(){ - if(!type || $(this).hasClass(type)){ - $(this).show(); - } - else { - $(this).hide(); - } - }); +function filterchanges(type) { + $("ul.changes li").each(function () { + if (!type || $(this).hasClass(type)) { + $(this).show(); + } else { + $(this).hide(); + } + }); } -$(document).ready(function(){ - dropdowns(); -}); \ No newline at end of file +$(document).ready(function () { + dropdowns(); +}); diff --git a/html/create_object.html b/html/create_object.html index c9b8b091b3a..92f4bf29e89 100644 --- a/html/create_object.html +++ b/html/create_object.html @@ -1,129 +1,149 @@ + + Create Object + + - h1, h2, h3, h4, h5, h6 - { - color: #00f; - font-family: Georgia, Arial, sans-serif; - } - img { - border: 0px; - } - p.lic { - font-size: 6pt; - } - - + +
+ + /* hreftokenfield */ + - - - - /* hreftokenfield */ - + Type + +
+ Offset: + - Type
- Offset: + A R +
- A - R
+ Number: + + Dir: + + Name: +
+ Where: + +

+ Number of matches: +
+

- Number: - Dir: - Name:
- Where: - -

- Number of matches:
-

+
+ +
-
- -
+
+ +
-
- - + - + function submitFirst(event) { + if (!object_list.options.length) { + return false; + } + if (event.keyCode == 13 || event.which == 13) { + object_list.options[0].selected = "true"; + } + } + + diff --git a/html/shock.js b/html/shock.js index 68ad8b61a41..4afce1a5542 100644 --- a/html/shock.js +++ b/html/shock.js @@ -4,16 +4,17 @@ let lastCall; const reactRoot = document.getElementById("react-root"); if (reactRoot) { - reactRoot.innerHTML = "

You shouldn't see this window, update your skin.

"; + reactRoot.innerHTML = + "

You shouldn't see this window, update your skin.

"; } Byond.subscribeTo("estop", function () { if (webSocket) { webSocket.close(); } else { - Byond.sendMessage("disconnected"); - } -}) + Byond.sendMessage("disconnected"); + } +}); Byond.subscribeTo("connect", function (data) { if (webSocket) { @@ -30,9 +31,9 @@ Byond.subscribeTo("connect", function (data) { webSocket.onerror = (ev) => { Byond.sendMessage("error", ev); }; - webSocket.onclose = (ev) => { - Byond.sendMessage("disconnected"); - } + webSocket.onclose = (ev) => { + Byond.sendMessage("disconnected"); + }; webSocket.onmessage = (ev) => { Byond.sendMessage("incomingMessage", { data: ev.data, lastCall }); }; @@ -63,17 +64,17 @@ Byond.subscribeTo("shock", function (data) { lastCall = "operate"; webSocket.sendJson({ - "cmd": "operate", - "value": { - "intensity": data.intensity, // 1 - 100 - int - "duration": data.duration, // 0.1 - 15 - float - "shocker_option": "all", // all, random - "action": "shock", // shock, vibrate, beep, end - "shocker_ids": data.shocker_ids, // [] - List of shocker ids - "device_ids": [], // [] - list of pishock client ids, if one of these is provided it will activate all shockers associated with it - "warning": data.warning, // true, false - will send a vibrate with the same intensity and duration - "held": false, // true, false - for continuous commands + cmd: "operate", + value: { + intensity: data.intensity, // 1 - 100 - int + duration: data.duration, // 0.1 - 15 - float + shocker_option: "all", // all, random + action: "shock", // shock, vibrate, beep, end + shocker_ids: data.shocker_ids, // [] - List of shocker ids + device_ids: [], // [] - list of pishock client ids, if one of these is provided it will activate all shockers associated with it + warning: data.warning, // true, false - will send a vibrate with the same intensity and duration + held: false, // true, false - for continuous commands }, - "auth_key": authKey, + auth_key: authKey, }); }); diff --git a/html/statbrowser.css b/html/statbrowser.css index d3084d53cb0..c5fcdc31402 100644 --- a/html/statbrowser.css +++ b/html/statbrowser.css @@ -255,52 +255,52 @@ body.dark { /* required for alt click menu */ .link { - display: inline; - background: none; - border: none; - padding: 7px 14px; - color: black; - text-decoration: none; - cursor: pointer; - font-size: 13px; - margin: 2px 2px; + display: inline; + background: none; + border: none; + padding: 7px 14px; + color: black; + text-decoration: none; + cursor: pointer; + font-size: 13px; + margin: 2px 2px; } .linkelem { - display: inline; - background: none; - border: none; - padding: 0px 14px; - color: black; - text-decoration: none; - cursor: pointer; - font-size: 13px; - margin: 2px 2px; + display: inline; + background: none; + border: none; + padding: 0px 14px; + color: black; + text-decoration: none; + cursor: pointer; + font-size: 13px; + margin: 2px 2px; } .dark .link { - color: #abc6ec; + color: #abc6ec; } .dark .linkelem { - color: #abc6ec; + color: #abc6ec; } .link:hover { - text-decoration: underline; + text-decoration: underline; } .linkelem:hover { - text-decoration: underline; + text-decoration: underline; } -.spoiler{ - background-color: gray; - color: transparent; - user-select: none; +.spoiler { + background-color: gray; + color: transparent; + user-select: none; } -.spoiler:hover{ - background-color: inherit; - color: inherit; +.spoiler:hover { + background-color: inherit; + color: inherit; } diff --git a/html/statbrowser.html b/html/statbrowser.html index ffd7425bd26..b1f17b826b3 100644 --- a/html/statbrowser.html +++ b/html/statbrowser.html @@ -1,5 +1,5 @@
- -
-
+ +
+
diff --git a/html/statbrowser.js b/html/statbrowser.js index 5ce7ace833d..d339809a1ea 100644 --- a/html/statbrowser.js +++ b/html/statbrowser.js @@ -1,17 +1,17 @@ // Polyfills and compatibility ------------------------------------------------ var decoder = decodeURIComponent || unescape; if (!Array.prototype.includes) { - Array.prototype.includes = function (thing) { - for (var i = 0; i < this.length; i++) { - if (this[i] == thing) return true; - } - return false; - }; + Array.prototype.includes = function (thing) { + for (var i = 0; i < this.length; i++) { + if (this[i] == thing) return true; + } + return false; + }; } if (!String.prototype.trim) { - String.prototype.trim = function () { - return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); - }; + String.prototype.trim = function () { + return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); + }; } // Status panel implementation ------------------------------------------------ @@ -41,1055 +41,1055 @@ var split_admin_tabs = false; // to ensure that when we relinquish our focus, we don't do it after the result of // a command has already taken focus for itself. function run_after_focus(callback) { - setTimeout(callback, 0); + setTimeout(callback, 0); } function createStatusTab(name) { - if (name.indexOf(".") != -1) { - var splitName = name.split("."); - if (split_admin_tabs && splitName[0] === "Admin") name = splitName[1]; - else name = splitName[0]; - } - if (document.getElementById(name) || name.trim() == "") { - return; - } - if (!verb_tabs.includes(name) && !permanent_tabs.includes(name)) { - return; - } - var button = document.createElement("DIV"); - button.onclick = function () { - tab_change(name); - this.blur(); - statcontentdiv.focus(); - }; - button.id = name; - button.textContent = name; - button.className = "button"; - //ORDERING ALPHABETICALLY - button.style.order = name.charCodeAt(0); - if (name == "Status" || name == "MC") { - button.style.order = name == "Status" ? 1 : 2; - } - if (name == "Tickets") { - button.style.order = 3; - } - //END ORDERING - menu.appendChild(button); - SendTabToByond(name); + if (name.indexOf(".") != -1) { + var splitName = name.split("."); + if (split_admin_tabs && splitName[0] === "Admin") name = splitName[1]; + else name = splitName[0]; + } + if (document.getElementById(name) || name.trim() == "") { + return; + } + if (!verb_tabs.includes(name) && !permanent_tabs.includes(name)) { + return; + } + var button = document.createElement("DIV"); + button.onclick = function () { + tab_change(name); + this.blur(); + statcontentdiv.focus(); + }; + button.id = name; + button.textContent = name; + button.className = "button"; + //ORDERING ALPHABETICALLY + button.style.order = name.charCodeAt(0); + if (name == "Status" || name == "MC") { + button.style.order = name == "Status" ? 1 : 2; + } + if (name == "Tickets") { + button.style.order = 3; + } + //END ORDERING + menu.appendChild(button); + SendTabToByond(name); } function removeStatusTab(name) { - if (!document.getElementById(name) || permanent_tabs.includes(name)) { - return; - } - for (var i = verb_tabs.length - 1; i >= 0; --i) { - if (verb_tabs[i] == name) { - verb_tabs.splice(i, 1); - } - } - if (current_tab == name) { - tab_change("Status"); - } - menu.removeChild(document.getElementById(name)); - TakeTabFromByond(name); + if (!document.getElementById(name) || permanent_tabs.includes(name)) { + return; + } + for (var i = verb_tabs.length - 1; i >= 0; --i) { + if (verb_tabs[i] == name) { + verb_tabs.splice(i, 1); + } + } + if (current_tab == name) { + tab_change("Status"); + } + menu.removeChild(document.getElementById(name)); + TakeTabFromByond(name); } function sortVerbs() { - verbs.sort(function (a, b) { - var selector = a[0] == b[0] ? 1 : 0; - if (a[selector].toUpperCase() < b[selector].toUpperCase()) { - return 1; - } else if (a[selector].toUpperCase() > b[selector].toUpperCase()) { - return -1; - } - return 0; - }); + verbs.sort(function (a, b) { + var selector = a[0] == b[0] ? 1 : 0; + if (a[selector].toUpperCase() < b[selector].toUpperCase()) { + return 1; + } else if (a[selector].toUpperCase() > b[selector].toUpperCase()) { + return -1; + } + return 0; + }); } function addPermanentTab(name) { - if (!permanent_tabs.includes(name)) { - permanent_tabs.push(name); - } - createStatusTab(name); + if (!permanent_tabs.includes(name)) { + permanent_tabs.push(name); + } + createStatusTab(name); } function removePermanentTab(name) { - for (var i = permanent_tabs.length - 1; i >= 0; --i) { - if (permanent_tabs[i] == name) { - permanent_tabs.splice(i, 1); - } - } - removeStatusTab(name); + for (var i = permanent_tabs.length - 1; i >= 0; --i) { + if (permanent_tabs[i] == name) { + permanent_tabs.splice(i, 1); + } + } + removeStatusTab(name); } function checkStatusTab() { - for (var i = 0; i < menu.children.length; i++) { - if ( - !verb_tabs.includes(menu.children[i].id) && - !permanent_tabs.includes(menu.children[i].id) - ) { - menu.removeChild(menu.children[i]); - } - } + for (var i = 0; i < menu.children.length; i++) { + if ( + !verb_tabs.includes(menu.children[i].id) && + !permanent_tabs.includes(menu.children[i].id) + ) { + menu.removeChild(menu.children[i]); + } + } } function remove_verb(v) { - var verb_to_remove = v; // to_remove = [verb:category, verb:name] - for (var i = verbs.length - 1; i >= 0; i--) { - var part_to_remove = verbs[i]; - if (part_to_remove[1] == verb_to_remove[1]) { - verbs.splice(i, 1); - } - } + var verb_to_remove = v; // to_remove = [verb:category, verb:name] + for (var i = verbs.length - 1; i >= 0; i--) { + var part_to_remove = verbs[i]; + if (part_to_remove[1] == verb_to_remove[1]) { + verbs.splice(i, 1); + } + } } function check_verbs() { - for (var v = verb_tabs.length - 1; v >= 0; v--) { - verbs_cat_check(verb_tabs[v]); - } + for (var v = verb_tabs.length - 1; v >= 0; v--) { + verbs_cat_check(verb_tabs[v]); + } } function verbs_cat_check(cat) { - var tabCat = cat; - if (cat.indexOf(".") != -1) { - var splitName = cat.split("."); - if (split_admin_tabs && splitName[0] === "Admin") tabCat = splitName[1]; - else tabCat = splitName[0]; - } - var verbs_in_cat = 0; - var verbcat = ""; - if (!verb_tabs.includes(tabCat)) { - removeStatusTab(tabCat); - return; - } - for (var v = 0; v < verbs.length; v++) { - var part = verbs[v]; - verbcat = part[0]; - if (verbcat.indexOf(".") != -1) { - var splitName = verbcat.split("."); - if (split_admin_tabs && splitName[0] === "Admin") verbcat = splitName[1]; - else verbcat = splitName[0]; - } - if (verbcat != tabCat || verbcat.trim() == "") { - continue; - } else { - verbs_in_cat = 1; - break; // we only need one - } - } - if (verbs_in_cat != 1) { - removeStatusTab(tabCat); - if (current_tab == tabCat) tab_change("Status"); - } + var tabCat = cat; + if (cat.indexOf(".") != -1) { + var splitName = cat.split("."); + if (split_admin_tabs && splitName[0] === "Admin") tabCat = splitName[1]; + else tabCat = splitName[0]; + } + var verbs_in_cat = 0; + var verbcat = ""; + if (!verb_tabs.includes(tabCat)) { + removeStatusTab(tabCat); + return; + } + for (var v = 0; v < verbs.length; v++) { + var part = verbs[v]; + verbcat = part[0]; + if (verbcat.indexOf(".") != -1) { + var splitName = verbcat.split("."); + if (split_admin_tabs && splitName[0] === "Admin") verbcat = splitName[1]; + else verbcat = splitName[0]; + } + if (verbcat != tabCat || verbcat.trim() == "") { + continue; + } else { + verbs_in_cat = 1; + break; // we only need one + } + } + if (verbs_in_cat != 1) { + removeStatusTab(tabCat); + if (current_tab == tabCat) tab_change("Status"); + } } function findVerbindex(name, verblist) { - for (var i = 0; i < verblist.length; i++) { - var part = verblist[i]; - if (part[1] == name) return i; - } + for (var i = 0; i < verblist.length; i++) { + var part = verblist[i]; + if (part[1] == name) return i; + } } function wipe_verbs() { - verbs = [["", ""]]; - verb_tabs = []; - checkStatusTab(); // remove all empty verb tabs + verbs = [["", ""]]; + verb_tabs = []; + checkStatusTab(); // remove all empty verb tabs } function update_verbs() { - wipe_verbs(); - Byond.sendMessage("Update-Verbs"); + wipe_verbs(); + Byond.sendMessage("Update-Verbs"); } function SendTabsToByond() { - var tabstosend = []; - tabstosend = tabstosend.concat(permanent_tabs, verb_tabs); - for (var i = 0; i < tabstosend.length; i++) { - SendTabToByond(tabstosend[i]); - } + var tabstosend = []; + tabstosend = tabstosend.concat(permanent_tabs, verb_tabs); + for (var i = 0; i < tabstosend.length; i++) { + SendTabToByond(tabstosend[i]); + } } function SendTabToByond(tab) { - Byond.sendMessage("Send-Tabs", { tab: tab }); + Byond.sendMessage("Send-Tabs", { tab: tab }); } //Byond can't have this tab anymore since we're removing it function TakeTabFromByond(tab) { - Byond.sendMessage("Remove-Tabs", { tab: tab }); + Byond.sendMessage("Remove-Tabs", { tab: tab }); } function spell_cat_check(cat) { - var spells_in_cat = 0; - var spellcat = ""; - for (var s = 0; s < spells.length; s++) { - var spell = spells[s]; - spellcat = spell[0]; - if (spellcat == cat) { - spells_in_cat++; - } - } - if (spells_in_cat < 1) { - removeStatusTab(cat); - } + var spells_in_cat = 0; + var spellcat = ""; + for (var s = 0; s < spells.length; s++) { + var spell = spells[s]; + spellcat = spell[0]; + if (spellcat == cat) { + spells_in_cat++; + } + } + if (spells_in_cat < 1) { + removeStatusTab(cat); + } } function tab_change(tab) { - if (tab == current_tab) return; - if (document.getElementById(current_tab)) - document.getElementById(current_tab).className = "button"; // disable active on last button - current_tab = tab; - set_byond_tab(tab); - if (document.getElementById(tab)) - document.getElementById(tab).className = "button active"; // make current button active - var spell_tabs_thingy = spell_tabs.includes(tab); - var verb_tabs_thingy = verb_tabs.includes(tab); - if (tab == "Status") { - draw_status(); - } else if (tab == "MC") { - draw_mc(); - } else if (spell_tabs_thingy) { - draw_spells(tab); - } else if (verb_tabs_thingy) { - draw_verbs(tab); - } else if (tab == "Debug Stat Panel") { - draw_debug(); - } else if (tab == "Tickets") { - draw_tickets(); - } else if (misc.has(tab)) { - draw_misc(tab); - } else if (tab == "Examine") { - draw_examine(); - } else if (tab == "SDQL2") { - draw_sdql2(); - } else if (tab == turfname) { - draw_listedturf(); - } else { - statcontentdiv.textContext = "Loading..."; - } - Byond.winset(Byond.windowId, { - "is-visible": true, - }); + if (tab == current_tab) return; + if (document.getElementById(current_tab)) + document.getElementById(current_tab).className = "button"; // disable active on last button + current_tab = tab; + set_byond_tab(tab); + if (document.getElementById(tab)) + document.getElementById(tab).className = "button active"; // make current button active + var spell_tabs_thingy = spell_tabs.includes(tab); + var verb_tabs_thingy = verb_tabs.includes(tab); + if (tab == "Status") { + draw_status(); + } else if (tab == "MC") { + draw_mc(); + } else if (spell_tabs_thingy) { + draw_spells(tab); + } else if (verb_tabs_thingy) { + draw_verbs(tab); + } else if (tab == "Debug Stat Panel") { + draw_debug(); + } else if (tab == "Tickets") { + draw_tickets(); + } else if (misc.has(tab)) { + draw_misc(tab); + } else if (tab == "Examine") { + draw_examine(); + } else if (tab == "SDQL2") { + draw_sdql2(); + } else if (tab == turfname) { + draw_listedturf(); + } else { + statcontentdiv.textContext = "Loading..."; + } + Byond.winset(Byond.windowId, { + "is-visible": true, + }); } function set_byond_tab(tab) { - Byond.sendMessage("Set-Tab", { tab: tab }); + Byond.sendMessage("Set-Tab", { tab: tab }); } function draw_examine() { - statcontentdiv.textContent = ""; - var div_content = document.createElement("div"); - for (var i = 0; i < examine.length; i++) { - var parameter = document.createElement("p"); - var textList = examine[i].split("||"); - if (textList.length > 1) { - for (var j = 0; j < textList.length; j++) { - var spoilerText = document.createElement("span"); - if (j % 2) { - spoilerText.className = "spoiler"; - } - spoilerText.innerHTML = textList[j]; - parameter.appendChild(spoilerText); - } - } else { - parameter.innerHTML = examine[i]; - } - div_content.appendChild(parameter); - } - var images = div_content.querySelectorAll("img"); - for (var i = 0; i < images.length; i++) { - images[i].addEventListener("error", iconError); - } - document.getElementById("statcontent").appendChild(div_content); + statcontentdiv.textContent = ""; + var div_content = document.createElement("div"); + for (var i = 0; i < examine.length; i++) { + var parameter = document.createElement("p"); + var textList = examine[i].split("||"); + if (textList.length > 1) { + for (var j = 0; j < textList.length; j++) { + var spoilerText = document.createElement("span"); + if (j % 2) { + spoilerText.className = "spoiler"; + } + spoilerText.innerHTML = textList[j]; + parameter.appendChild(spoilerText); + } + } else { + parameter.innerHTML = examine[i]; + } + div_content.appendChild(parameter); + } + var images = div_content.querySelectorAll("img"); + for (var i = 0; i < images.length; i++) { + images[i].addEventListener("error", iconError); + } + document.getElementById("statcontent").appendChild(div_content); } function draw_debug() { - statcontentdiv.textContent = ""; - var wipeverbstabs = document.createElement("div"); - var link = document.createElement("a"); - link.onclick = function () { - wipe_verbs(); - }; - link.textContent = "Wipe All Verbs"; - wipeverbstabs.appendChild(link); - document.getElementById("statcontent").appendChild(wipeverbstabs); - var wipeUpdateVerbsTabs = document.createElement("div"); - var updateLink = document.createElement("a"); - updateLink.onclick = function () { - update_verbs(); - }; - updateLink.textContent = "Wipe and Update All Verbs"; - wipeUpdateVerbsTabs.appendChild(updateLink); - document.getElementById("statcontent").appendChild(wipeUpdateVerbsTabs); - var text = document.createElement("div"); - text.textContent = "Verb Tabs:"; - document.getElementById("statcontent").appendChild(text); - var table1 = document.createElement("table"); - for (var i = 0; i < verb_tabs.length; i++) { - var part = verb_tabs[i]; - // Hide subgroups except admin subgroups if they are split - if (verb_tabs[i].lastIndexOf(".") != -1) { - var splitName = verb_tabs[i].split("."); - if (split_admin_tabs && splitName[0] === "Admin") part = splitName[1]; - else continue; - } - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part; - var a = document.createElement("a"); - a.onclick = (function (part) { - return function () { - removeStatusTab(part); - }; - })(part); - a.textContent = " Delete Tab " + part; - td1.appendChild(a); - tr.appendChild(td1); - table1.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table1); - var header2 = document.createElement("div"); - header2.textContent = "Verbs:"; - document.getElementById("statcontent").appendChild(header2); - var table2 = document.createElement("table"); - for (var v = 0; v < verbs.length; v++) { - var part2 = verbs[v]; - var trr = document.createElement("tr"); - var tdd1 = document.createElement("td"); - tdd1.textContent = part2[0]; - var tdd2 = document.createElement("td"); - tdd2.textContent = part2[1]; - trr.appendChild(tdd1); - trr.appendChild(tdd2); - table2.appendChild(trr); - } - document.getElementById("statcontent").appendChild(table2); - var text3 = document.createElement("div"); - text3.textContent = "Permanent Tabs:"; - document.getElementById("statcontent").appendChild(text3); - var table3 = document.createElement("table"); - for (var i = 0; i < permanent_tabs.length; i++) { - var part3 = permanent_tabs[i]; - var trrr = document.createElement("tr"); - var tddd1 = document.createElement("td"); - tddd1.textContent = part3; - trrr.appendChild(tddd1); - table3.appendChild(trrr); - } - document.getElementById("statcontent").appendChild(table3); + statcontentdiv.textContent = ""; + var wipeverbstabs = document.createElement("div"); + var link = document.createElement("a"); + link.onclick = function () { + wipe_verbs(); + }; + link.textContent = "Wipe All Verbs"; + wipeverbstabs.appendChild(link); + document.getElementById("statcontent").appendChild(wipeverbstabs); + var wipeUpdateVerbsTabs = document.createElement("div"); + var updateLink = document.createElement("a"); + updateLink.onclick = function () { + update_verbs(); + }; + updateLink.textContent = "Wipe and Update All Verbs"; + wipeUpdateVerbsTabs.appendChild(updateLink); + document.getElementById("statcontent").appendChild(wipeUpdateVerbsTabs); + var text = document.createElement("div"); + text.textContent = "Verb Tabs:"; + document.getElementById("statcontent").appendChild(text); + var table1 = document.createElement("table"); + for (var i = 0; i < verb_tabs.length; i++) { + var part = verb_tabs[i]; + // Hide subgroups except admin subgroups if they are split + if (verb_tabs[i].lastIndexOf(".") != -1) { + var splitName = verb_tabs[i].split("."); + if (split_admin_tabs && splitName[0] === "Admin") part = splitName[1]; + else continue; + } + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part; + var a = document.createElement("a"); + a.onclick = (function (part) { + return function () { + removeStatusTab(part); + }; + })(part); + a.textContent = " Delete Tab " + part; + td1.appendChild(a); + tr.appendChild(td1); + table1.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table1); + var header2 = document.createElement("div"); + header2.textContent = "Verbs:"; + document.getElementById("statcontent").appendChild(header2); + var table2 = document.createElement("table"); + for (var v = 0; v < verbs.length; v++) { + var part2 = verbs[v]; + var trr = document.createElement("tr"); + var tdd1 = document.createElement("td"); + tdd1.textContent = part2[0]; + var tdd2 = document.createElement("td"); + tdd2.textContent = part2[1]; + trr.appendChild(tdd1); + trr.appendChild(tdd2); + table2.appendChild(trr); + } + document.getElementById("statcontent").appendChild(table2); + var text3 = document.createElement("div"); + text3.textContent = "Permanent Tabs:"; + document.getElementById("statcontent").appendChild(text3); + var table3 = document.createElement("table"); + for (var i = 0; i < permanent_tabs.length; i++) { + var part3 = permanent_tabs[i]; + var trrr = document.createElement("tr"); + var tddd1 = document.createElement("td"); + tddd1.textContent = part3; + trrr.appendChild(tddd1); + table3.appendChild(trrr); + } + document.getElementById("statcontent").appendChild(table3); } function draw_status() { - if (!document.getElementById("Status")) { - createStatusTab("Status"); - current_tab = "Status"; - } - statcontentdiv.textContent = ""; - for (var i = 0; i < status_tab_parts.length; i++) { - if (status_tab_parts[i].trim() == "") { - document - .getElementById("statcontent") - .appendChild(document.createElement("br")); - } else { - var div = document.createElement("div"); - div.textContent = status_tab_parts[i]; - div.className = "status-info"; - document.getElementById("statcontent").appendChild(div); - } - } - if (verb_tabs.length == 0 || !verbs) { - Byond.command("Fix-Stat-Panel"); - } + if (!document.getElementById("Status")) { + createStatusTab("Status"); + current_tab = "Status"; + } + statcontentdiv.textContent = ""; + for (var i = 0; i < status_tab_parts.length; i++) { + if (status_tab_parts[i].trim() == "") { + document + .getElementById("statcontent") + .appendChild(document.createElement("br")); + } else { + var div = document.createElement("div"); + div.textContent = status_tab_parts[i]; + div.className = "status-info"; + document.getElementById("statcontent").appendChild(div); + } + } + if (verb_tabs.length == 0 || !verbs) { + Byond.command("Fix-Stat-Panel"); + } } function draw_mc() { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - for (var i = 0; i < mc_tab_parts.length; i++) { - var part = mc_tab_parts[i]; - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part[0]; - var td2 = document.createElement("td"); - if (part[2]) { - var a = document.createElement("a"); - a.href = - "byond://?_src_=vars;admin_token=" + href_token + ";Vars=" + part[2]; - a.textContent = part[1]; - td2.appendChild(a); - } else { - td2.textContent = part[1]; - } - tr.appendChild(td1); - tr.appendChild(td2); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < mc_tab_parts.length; i++) { + var part = mc_tab_parts[i]; + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part[0]; + var td2 = document.createElement("td"); + if (part[2]) { + var a = document.createElement("a"); + a.href = + "byond://?_src_=vars;admin_token=" + href_token + ";Vars=" + part[2]; + a.textContent = part[1]; + td2.appendChild(a); + } else { + td2.textContent = part[1]; + } + tr.appendChild(td1); + tr.appendChild(td2); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function remove_tickets() { - if (tickets) { - tickets = []; - removePermanentTab("Tickets"); - if (current_tab == "Tickets") tab_change("Status"); - } - checkStatusTab(); + if (tickets) { + tickets = []; + removePermanentTab("Tickets"); + if (current_tab == "Tickets") tab_change("Status"); + } + checkStatusTab(); } function remove_sdql2() { - if (sdql2) { - sdql2 = []; - removePermanentTab("SDQL2"); - if (current_tab == "SDQL2") tab_change("Status"); - } - checkStatusTab(); + if (sdql2) { + sdql2 = []; + removePermanentTab("SDQL2"); + if (current_tab == "SDQL2") tab_change("Status"); + } + checkStatusTab(); } function iconError(e) { - setTimeout(function () { - if (current_tab != turfname && current_tab != "Examine") { - return; - } - var node = e.target; - var current_attempts = Number(node.getAttribute("data-attempts")) || 0; - if (current_attempts > imageRetryLimit) { - return; - } - var src = node.src; - node.src = null; - node.src = src + "#" + current_attempts; - node.setAttribute("data-attempts", current_attempts + 1); - }, imageRetryDelay); + setTimeout(function () { + if (current_tab != turfname && current_tab != "Examine") { + return; + } + var node = e.target; + var current_attempts = Number(node.getAttribute("data-attempts")) || 0; + if (current_attempts > imageRetryLimit) { + return; + } + var src = node.src; + node.src = null; + node.src = src + "#" + current_attempts; + node.setAttribute("data-attempts", current_attempts + 1); + }, imageRetryDelay); } function draw_listedturf() { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - for (var i = 0; i < turfcontents.length; i++) { - var part = turfcontents[i]; - if (storedimages[part[1]] == null && part[2]) { - var img = document.createElement("img"); - img.src = part[2]; - img.id = part[1]; - storedimages[part[1]] = part[2]; - img.onerror = iconError; - table.appendChild(img); - } else { - var img = document.createElement("img"); - img.onerror = iconError; - img.src = storedimages[part[1]]; - img.id = part[1]; - table.appendChild(img); - } - var b = document.createElement("div"); - b.className = "link"; - b.onmousedown = (function (part) { - // The outer function is used to close over a fresh "part" variable, - // rather than every onmousedown getting the "part" of the last entry. - return function (e) { - e.preventDefault(); - var params = { src: part[1] }; - switch (e.button) { - case 1: - params["statpanel_item_click"] = "middle"; - break; - case 2: - params["statpanel_item_click"] = "right"; - break; - default: - params["statpanel_item_click"] = "left"; - } - if (e.shiftKey) { - params["statpanel_item_shiftclick"] = 1; - } - if (e.ctrlKey) { - params["statpanel_item_ctrlclick"] = 1; - } - if (e.altKey) { - params["statpanel_item_altclick"] = 1; - } - Byond.topic(params); - }; - })(part); - b.textContent = part[0]; - table.appendChild(b); - table.appendChild(document.createElement("br")); - } - statcontentdiv.appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < turfcontents.length; i++) { + var part = turfcontents[i]; + if (storedimages[part[1]] == null && part[2]) { + var img = document.createElement("img"); + img.src = part[2]; + img.id = part[1]; + storedimages[part[1]] = part[2]; + img.onerror = iconError; + table.appendChild(img); + } else { + var img = document.createElement("img"); + img.onerror = iconError; + img.src = storedimages[part[1]]; + img.id = part[1]; + table.appendChild(img); + } + var b = document.createElement("div"); + b.className = "link"; + b.onmousedown = (function (part) { + // The outer function is used to close over a fresh "part" variable, + // rather than every onmousedown getting the "part" of the last entry. + return function (e) { + e.preventDefault(); + var params = { src: part[1] }; + switch (e.button) { + case 1: + params["statpanel_item_click"] = "middle"; + break; + case 2: + params["statpanel_item_click"] = "right"; + break; + default: + params["statpanel_item_click"] = "left"; + } + if (e.shiftKey) { + params["statpanel_item_shiftclick"] = 1; + } + if (e.ctrlKey) { + params["statpanel_item_ctrlclick"] = 1; + } + if (e.altKey) { + params["statpanel_item_altclick"] = 1; + } + Byond.topic(params); + }; + })(part); + b.textContent = part[0]; + table.appendChild(b); + table.appendChild(document.createElement("br")); + } + statcontentdiv.appendChild(table); } function remove_listedturf() { - removePermanentTab(turfname); - checkStatusTab(); - if (current_tab == turfname) { - tab_change("Status"); - } + removePermanentTab(turfname); + checkStatusTab(); + if (current_tab == turfname) { + tab_change("Status"); + } } function remove_mc() { - removePermanentTab("MC"); - if (current_tab == "MC") { - tab_change("Status"); - } + removePermanentTab("MC"); + if (current_tab == "MC") { + tab_change("Status"); + } } function draw_sdql2() { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - for (var i = 0; i < sdql2.length; i++) { - var part = sdql2[i]; - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part[0]; - var td2 = document.createElement("td"); - if (part[2]) { - var a = document.createElement("a"); - a.href = "byond://?src=" + part[2] + ";statpanel_item_click=left"; - a.textContent = part[1]; - td2.appendChild(a); - } else { - td2.textContent = part[1]; - } - tr.appendChild(td1); - tr.appendChild(td2); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < sdql2.length; i++) { + var part = sdql2[i]; + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part[0]; + var td2 = document.createElement("td"); + if (part[2]) { + var a = document.createElement("a"); + a.href = "byond://?src=" + part[2] + ";statpanel_item_click=left"; + a.textContent = part[1]; + td2.appendChild(a); + } else { + td2.textContent = part[1]; + } + tr.appendChild(td1); + tr.appendChild(td2); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function draw_tickets() { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - if (!tickets) { - return; - } - for (var i = 0; i < tickets.length; i++) { - var part = tickets[i]; - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part[0]; - var td2 = document.createElement("td"); - if (part[2]) { - var a = document.createElement("a"); - a.href = - "byond://?_src_=holder;admin_token=" + - href_token + - ";ahelp=" + - part[2] + - ";ahelp_action=ticket;statpanel_item_click=left;action=ticket"; - a.textContent = part[1]; - td2.appendChild(a); - } else if (part[3]) { - var a = document.createElement("a"); - a.href = "byond://?src=" + part[3] + ";statpanel_item_click=left"; - a.textContent = part[1]; - td2.appendChild(a); - } else { - td2.textContent = part[1]; - } - tr.appendChild(td1); - tr.appendChild(td2); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + if (!tickets) { + return; + } + for (var i = 0; i < tickets.length; i++) { + var part = tickets[i]; + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part[0]; + var td2 = document.createElement("td"); + if (part[2]) { + var a = document.createElement("a"); + a.href = + "byond://?_src_=holder;admin_token=" + + href_token + + ";ahelp=" + + part[2] + + ";ahelp_action=ticket;statpanel_item_click=left;action=ticket"; + a.textContent = part[1]; + td2.appendChild(a); + } else if (part[3]) { + var a = document.createElement("a"); + a.href = "byond://?src=" + part[3] + ";statpanel_item_click=left"; + a.textContent = part[1]; + td2.appendChild(a); + } else { + td2.textContent = part[1]; + } + tr.appendChild(td1); + tr.appendChild(td2); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function draw_misc(tab) { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - table.className = "elemcontainer"; - let data = misc.get(tab); - if (!data) { - return; - } - for (var i = 0; i < data.length; i++) { - var tr = document.createElement("tr"); - var part = data[i]; + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + table.className = "elemcontainer"; + let data = misc.get(tab); + if (!data) { + return; + } + for (var i = 0; i < data.length; i++) { + var tr = document.createElement("tr"); + var part = data[i]; - var td1 = document.createElement("td"); - if (part[0]) { - td1.className = "elem"; - td1.textContent = part[0]; - } + var td1 = document.createElement("td"); + if (part[0]) { + td1.className = "elem"; + td1.textContent = part[0]; + } - var td2 = null; - if (part[1] && storedimages[part[1]] == null && part[2]) { - td2 = document.createElement("td"); - var img = document.createElement("img"); - img.src = part[2]; - img.id = part[1]; - storedimages[part[1]] = part[2]; - td2.appendChild(img); - } else if (part[1]) { - td2 = document.createElement("td"); - var img = document.createElement("img"); - img.src = storedimages[part[1]]; - img.id = part[1]; - td2.appendChild(img); - } - var td3 = null; - var b = document.createElement("div"); - if (part[4]) { - b.className = "linkelem"; - b.onmousedown = (function (part) { - // The outer function is used to close over a fresh "part" variable, - // rather than every onmousedown getting the "part" of the last entry. - return function (e) { - e.preventDefault(); - var params = { src: part[4] }; - switch (e.button) { - case 1: - params["statpanel_item_click"] = "middle"; - break; - case 2: - params["statpanel_item_click"] = "right"; - break; - default: - params["statpanel_item_click"] = "left"; - } - if (e.shiftKey) { - params["statpanel_item_shiftclick"] = 1; - } - if (e.ctrlKey) { - params["statpanel_item_ctrlclick"] = 1; - } - if (e.altKey) { - params["statpanel_item_altclick"] = 1; - } - Byond.topic(params); - }; - })(part); - } - if (part[3]) { - td3 = document.createElement("td"); - b.textContent = part[3]; - td3.appendChild(b); - } - if (!td2 && !td3) { - td1.className = "elem_span3"; - td1.colSpan += 2; - } else if (!td2) { - td1.className = "elem_span2"; - td1.colSpan += 1; - } else if (!td3) { - td2.colSpan += 1; - } - tr.appendChild(td1); - if (td2) { - tr.appendChild(td2); - } - if (td3) { - tr.appendChild(td3); - } - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + var td2 = null; + if (part[1] && storedimages[part[1]] == null && part[2]) { + td2 = document.createElement("td"); + var img = document.createElement("img"); + img.src = part[2]; + img.id = part[1]; + storedimages[part[1]] = part[2]; + td2.appendChild(img); + } else if (part[1]) { + td2 = document.createElement("td"); + var img = document.createElement("img"); + img.src = storedimages[part[1]]; + img.id = part[1]; + td2.appendChild(img); + } + var td3 = null; + var b = document.createElement("div"); + if (part[4]) { + b.className = "linkelem"; + b.onmousedown = (function (part) { + // The outer function is used to close over a fresh "part" variable, + // rather than every onmousedown getting the "part" of the last entry. + return function (e) { + e.preventDefault(); + var params = { src: part[4] }; + switch (e.button) { + case 1: + params["statpanel_item_click"] = "middle"; + break; + case 2: + params["statpanel_item_click"] = "right"; + break; + default: + params["statpanel_item_click"] = "left"; + } + if (e.shiftKey) { + params["statpanel_item_shiftclick"] = 1; + } + if (e.ctrlKey) { + params["statpanel_item_ctrlclick"] = 1; + } + if (e.altKey) { + params["statpanel_item_altclick"] = 1; + } + Byond.topic(params); + }; + })(part); + } + if (part[3]) { + td3 = document.createElement("td"); + b.textContent = part[3]; + td3.appendChild(b); + } + if (!td2 && !td3) { + td1.className = "elem_span3"; + td1.colSpan += 2; + } else if (!td2) { + td1.className = "elem_span2"; + td1.colSpan += 1; + } else if (!td3) { + td2.colSpan += 1; + } + tr.appendChild(td1); + if (td2) { + tr.appendChild(td2); + } + if (td3) { + tr.appendChild(td3); + } + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function draw_spells(cat) { - statcontentdiv.textContent = ""; - var table = document.createElement("table"); - for (var i = 0; i < spells.length; i++) { - var part = spells[i]; - if (part[0] != cat) continue; - var tr = document.createElement("tr"); - var td1 = document.createElement("td"); - td1.textContent = part[1]; - var td2 = document.createElement("td"); - if (part[3]) { - var a = document.createElement("a"); - a.href = "byond://?src=" + part[3] + ";statpanel_item_click=left"; - a.textContent = part[2]; - td2.appendChild(a); - } else { - td2.textContent = part[2]; - } - tr.appendChild(td1); - tr.appendChild(td2); - table.appendChild(tr); - } - document.getElementById("statcontent").appendChild(table); + statcontentdiv.textContent = ""; + var table = document.createElement("table"); + for (var i = 0; i < spells.length; i++) { + var part = spells[i]; + if (part[0] != cat) continue; + var tr = document.createElement("tr"); + var td1 = document.createElement("td"); + td1.textContent = part[1]; + var td2 = document.createElement("td"); + if (part[3]) { + var a = document.createElement("a"); + a.href = "byond://?src=" + part[3] + ";statpanel_item_click=left"; + a.textContent = part[2]; + td2.appendChild(a); + } else { + td2.textContent = part[2]; + } + tr.appendChild(td1); + tr.appendChild(td2); + table.appendChild(tr); + } + document.getElementById("statcontent").appendChild(table); } function make_verb_onclick(command) { - return function () { - run_after_focus(function () { - Byond.command(command); - }); - }; + return function () { + run_after_focus(function () { + Byond.command(command); + }); + }; } function draw_verbs(cat) { - statcontentdiv.textContent = ""; - var table = document.createElement("div"); - var additions = {}; // additional sub-categories to be rendered - table.className = "grid-container"; - sortVerbs(); - if (split_admin_tabs && cat.lastIndexOf(".") != -1) { - var splitName = cat.split("."); - if (splitName[0] === "Admin") cat = splitName[1]; - } - verbs.reverse(); // sort verbs backwards before we draw - for (var i = 0; i < verbs.length; ++i) { - var part = verbs[i]; - var name = part[0]; - if (split_admin_tabs && name.lastIndexOf(".") != -1) { - var splitName = name.split("."); - if (splitName[0] === "Admin") name = splitName[1]; - } - var command = part[1]; - var desc = part[2]; + statcontentdiv.textContent = ""; + var table = document.createElement("div"); + var additions = {}; // additional sub-categories to be rendered + table.className = "grid-container"; + sortVerbs(); + if (split_admin_tabs && cat.lastIndexOf(".") != -1) { + var splitName = cat.split("."); + if (splitName[0] === "Admin") cat = splitName[1]; + } + verbs.reverse(); // sort verbs backwards before we draw + for (var i = 0; i < verbs.length; ++i) { + var part = verbs[i]; + var name = part[0]; + if (split_admin_tabs && name.lastIndexOf(".") != -1) { + var splitName = name.split("."); + if (splitName[0] === "Admin") name = splitName[1]; + } + var command = part[1]; + var desc = part[2]; - if ( - command && - name.lastIndexOf(cat, 0) != -1 && - (name.length == cat.length || name.charAt(cat.length) == ".") - ) { - var subCat = name.lastIndexOf(".") != -1 ? name.split(".")[1] : null; - if (subCat && !additions[subCat]) { - var newTable = document.createElement("div"); - newTable.className = "grid-container"; - additions[subCat] = newTable; - } + if ( + command && + name.lastIndexOf(cat, 0) != -1 && + (name.length == cat.length || name.charAt(cat.length) == ".") + ) { + var subCat = name.lastIndexOf(".") != -1 ? name.split(".")[1] : null; + if (subCat && !additions[subCat]) { + var newTable = document.createElement("div"); + newTable.className = "grid-container"; + additions[subCat] = newTable; + } - var a = document.createElement("a"); - a.href = "#"; - a.onclick = make_verb_onclick(command.replace(/\s/g, "-")); - a.className = "grid-item"; - a.title = desc || "No description"; - var t = document.createElement("span"); - t.textContent = command; - t.className = "grid-item-text"; - a.appendChild(t); - (subCat ? additions[subCat] : table).appendChild(a); - } - } + var a = document.createElement("a"); + a.href = "#"; + a.onclick = make_verb_onclick(command.replace(/\s/g, "-")); + a.className = "grid-item"; + a.title = desc || "No description"; + var t = document.createElement("span"); + t.textContent = command; + t.className = "grid-item-text"; + a.appendChild(t); + (subCat ? additions[subCat] : table).appendChild(a); + } + } - // Append base table to view - var content = document.getElementById("statcontent"); - content.appendChild(table); + // Append base table to view + var content = document.getElementById("statcontent"); + content.appendChild(table); - // Append additional sub-categories if relevant - for (var cat in additions) { - if (additions.hasOwnProperty(cat)) { - // do addition here - var header = document.createElement("h3"); - header.textContent = cat; - content.appendChild(header); - content.appendChild(additions[cat]); - } - } + // Append additional sub-categories if relevant + for (var cat in additions) { + if (additions.hasOwnProperty(cat)) { + // do addition here + var header = document.createElement("h3"); + header.textContent = cat; + content.appendChild(header); + content.appendChild(additions[cat]); + } + } } function set_theme(which) { - if (which == "light" || which == "vchatlight") { - document.body.className = ""; - document.documentElement.className = "light"; - } else if (which == "dark" || which == "vchatdark") { - document.body.className = "dark"; - document.documentElement.className = "dark"; - } + if (which == "light" || which == "vchatlight") { + document.body.className = ""; + document.documentElement.className = "light"; + } else if (which == "dark" || which == "vchatdark") { + document.body.className = "dark"; + document.documentElement.className = "dark"; + } } function set_font_size(size) { - document.body.style.setProperty("font-size", size); + document.body.style.setProperty("font-size", size); } function set_tabs_style(style) { - if (style == "default") { - menu.classList.add("menu-wrap"); - menu.classList.remove("tabs-classic"); - } else if (style == "classic") { - menu.classList.add("menu-wrap"); - menu.classList.add("tabs-classic"); - } else if (style == "scrollable") { - menu.classList.remove("menu-wrap"); - menu.classList.remove("tabs-classic"); - } + if (style == "default") { + menu.classList.add("menu-wrap"); + menu.classList.remove("tabs-classic"); + } else if (style == "classic") { + menu.classList.add("menu-wrap"); + menu.classList.add("tabs-classic"); + } else if (style == "scrollable") { + menu.classList.remove("menu-wrap"); + menu.classList.remove("tabs-classic"); + } } function restoreFocus() { - run_after_focus(function () { - Byond.winset("map", { - focus: true, - }); - }); + run_after_focus(function () { + Byond.winset("map", { + focus: true, + }); + }); } function getCookie(cname) { - var name = cname + "="; - var ca = document.cookie.split(";"); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) == " ") c = c.substring(1); - if (c.indexOf(name) === 0) { - return decoder(c.substring(name.length, c.length)); - } - } - return ""; + var name = cname + "="; + var ca = document.cookie.split(";"); + for (var i = 0; i < ca.length; i++) { + var c = ca[i]; + while (c.charAt(0) == " ") c = c.substring(1); + if (c.indexOf(name) === 0) { + return decoder(c.substring(name.length, c.length)); + } + } + return ""; } function add_verb_list(payload) { - var to_add = payload; // list of a list with category and verb inside it - to_add.sort(); // sort what we're adding - for (var i = 0; i < to_add.length; i++) { - var part = to_add[i]; - if (!part[0]) continue; - var category = part[0]; - if (category.indexOf(".") != -1) { - var splitName = category.split("."); - if (split_admin_tabs && splitName[0] === "Admin") category = splitName[1]; - else category = splitName[0]; - } - if (findVerbindex(part[1], verbs)) continue; - if (verb_tabs.includes(category)) { - verbs.push(part); - if (current_tab == category) { - draw_verbs(category); // redraw if we added a verb to the tab we're currently in - } - } else if (category) { - verb_tabs.push(category); - verbs.push(part); - createStatusTab(category); - } - } + var to_add = payload; // list of a list with category and verb inside it + to_add.sort(); // sort what we're adding + for (var i = 0; i < to_add.length; i++) { + var part = to_add[i]; + if (!part[0]) continue; + var category = part[0]; + if (category.indexOf(".") != -1) { + var splitName = category.split("."); + if (split_admin_tabs && splitName[0] === "Admin") category = splitName[1]; + else category = splitName[0]; + } + if (findVerbindex(part[1], verbs)) continue; + if (verb_tabs.includes(category)) { + verbs.push(part); + if (current_tab == category) { + draw_verbs(category); // redraw if we added a verb to the tab we're currently in + } + } else if (category) { + verb_tabs.push(category); + verbs.push(part); + createStatusTab(category); + } + } } function init_spells() { - var cat = ""; - for (var i = 0; i < spell_tabs.length; i++) { - cat = spell_tabs[i]; - if (cat.length > 0) { - verb_tabs.push(cat); - createStatusTab(cat); - } - } + var cat = ""; + for (var i = 0; i < spell_tabs.length; i++) { + cat = spell_tabs[i]; + if (cat.length > 0) { + verb_tabs.push(cat); + createStatusTab(cat); + } + } } document.addEventListener("mouseup", restoreFocus); document.addEventListener("keyup", restoreFocus); if (!current_tab) { - addPermanentTab("Status"); - tab_change("Status"); + addPermanentTab("Status"); + tab_change("Status"); } window.onload = function () { - Byond.sendMessage("Update-Verbs"); + Byond.sendMessage("Update-Verbs"); }; Byond.subscribeTo("update_spells", function (payload) { - spell_tabs = payload.spell_tabs; - var do_update = false; - if (spell_tabs.includes(current_tab)) { - do_update = true; - } - init_spells(); - if (payload.actions) { - spells = payload.actions; - if (do_update) { - draw_spells(current_tab); - } - } else { - remove_spells(); - } + spell_tabs = payload.spell_tabs; + var do_update = false; + if (spell_tabs.includes(current_tab)) { + do_update = true; + } + init_spells(); + if (payload.actions) { + spells = payload.actions; + if (do_update) { + draw_spells(current_tab); + } + } else { + remove_spells(); + } }); Byond.subscribeTo("remove_verb_list", function (v) { - var to_remove = v; - for (var i = 0; i < to_remove.length; i++) { - remove_verb(to_remove[i]); - } - check_verbs(); - sortVerbs(); - if (verb_tabs.includes(current_tab)) draw_verbs(current_tab); + var to_remove = v; + for (var i = 0; i < to_remove.length; i++) { + remove_verb(to_remove[i]); + } + check_verbs(); + sortVerbs(); + if (verb_tabs.includes(current_tab)) draw_verbs(current_tab); }); // passes a 2D list of (verbcategory, verbname) creates tabs and adds verbs to respective list // example (IC, Say) Byond.subscribeTo("init_verbs", function (payload) { - wipe_verbs(); // remove all verb categories so we can replace them - checkStatusTab(); // remove all status tabs - verb_tabs = payload.panel_tabs; - verb_tabs.sort(); // sort it - var do_update = false; - var cat = ""; - for (var i = 0; i < verb_tabs.length; i++) { - cat = verb_tabs[i]; - createStatusTab(cat); // create a category if the verb doesn't exist yet - } - if (verb_tabs.includes(current_tab)) { - do_update = true; - } - if (payload.verblist) { - add_verb_list(payload.verblist); - sortVerbs(); // sort them - if (do_update) { - draw_verbs(current_tab); - } - } - SendTabsToByond(); + wipe_verbs(); // remove all verb categories so we can replace them + checkStatusTab(); // remove all status tabs + verb_tabs = payload.panel_tabs; + verb_tabs.sort(); // sort it + var do_update = false; + var cat = ""; + for (var i = 0; i < verb_tabs.length; i++) { + cat = verb_tabs[i]; + createStatusTab(cat); // create a category if the verb doesn't exist yet + } + if (verb_tabs.includes(current_tab)) { + do_update = true; + } + if (payload.verblist) { + add_verb_list(payload.verblist); + sortVerbs(); // sort them + if (do_update) { + draw_verbs(current_tab); + } + } + SendTabsToByond(); }); Byond.subscribeTo("update_stat", function (payload) { - status_tab_parts = [payload.ping_str]; - var parsed = payload.global_data; + status_tab_parts = [payload.ping_str]; + var parsed = payload.global_data; - for (var i = 0; i < parsed.length; i++) - if (parsed[i] != null) status_tab_parts.push(parsed[i]); + for (var i = 0; i < parsed.length; i++) + if (parsed[i] != null) status_tab_parts.push(parsed[i]); - parsed = payload.other_str; + parsed = payload.other_str; - for (var i = 0; i < parsed.length; i++) - if (parsed[i] != null) status_tab_parts.push(parsed[i]); + for (var i = 0; i < parsed.length; i++) + if (parsed[i] != null) status_tab_parts.push(parsed[i]); - if (current_tab == "Status") { - draw_status(); - } else if (current_tab == "Debug Stat Panel") { - draw_debug(); - } + if (current_tab == "Status") { + draw_status(); + } else if (current_tab == "Debug Stat Panel") { + draw_debug(); + } }); Byond.subscribeTo("update_mc", function (payload) { - mc_tab_parts = payload.mc_data; - mc_tab_parts.splice(0, 0, ["Location:", payload.coord_entry]); + mc_tab_parts = payload.mc_data; + mc_tab_parts.splice(0, 0, ["Location:", payload.coord_entry]); - if (!verb_tabs.includes("MC")) { - verb_tabs.push("MC"); - } + if (!verb_tabs.includes("MC")) { + verb_tabs.push("MC"); + } - createStatusTab("MC"); + createStatusTab("MC"); - if (current_tab == "MC") { - draw_mc(); - } + if (current_tab == "MC") { + draw_mc(); + } }); Byond.subscribeTo("remove_spells", function () { - for (var s = 0; s < spell_tabs.length; s++) { - removeStatusTab(spell_tabs[s]); - } + for (var s = 0; s < spell_tabs.length; s++) { + removeStatusTab(spell_tabs[s]); + } }); Byond.subscribeTo("init_spells", function () { - var cat = ""; - for (var i = 0; i < spell_tabs.length; i++) { - cat = spell_tabs[i]; - if (cat.length > 0) { - verb_tabs.push(cat); - createStatusTab(cat); - } - } + var cat = ""; + for (var i = 0; i < spell_tabs.length; i++) { + cat = spell_tabs[i]; + if (cat.length > 0) { + verb_tabs.push(cat); + createStatusTab(cat); + } + } }); Byond.subscribeTo("check_spells", function () { - for (var v = 0; v < spell_tabs.length; v++) { - spell_cat_check(spell_tabs[v]); - } + for (var v = 0; v < spell_tabs.length; v++) { + spell_cat_check(spell_tabs[v]); + } }); Byond.subscribeTo("create_debug", function () { - if (!document.getElementById("Debug Stat Panel")) { - addPermanentTab("Debug Stat Panel"); - } else { - removePermanentTab("Debug Stat Panel"); - } + if (!document.getElementById("Debug Stat Panel")) { + addPermanentTab("Debug Stat Panel"); + } else { + removePermanentTab("Debug Stat Panel"); + } }); Byond.subscribeTo("create_listedturf", function (TN) { - remove_listedturf(); // remove the last one if we had one - turfname = TN; - addPermanentTab(turfname); - tab_change(turfname); + remove_listedturf(); // remove the last one if we had one + turfname = TN; + addPermanentTab(turfname); + tab_change(turfname); }); Byond.subscribeTo("create_misc", function (TN) { - addPermanentTab(TN); + addPermanentTab(TN); }); Byond.subscribeTo("remove_misc", function (TN) { - removePermanentTab(TN); + removePermanentTab(TN); }); Byond.subscribeTo("remove_admin_tabs", function () { - href_token = null; - remove_mc(); - remove_tickets(); - remove_sdql2(); + href_token = null; + remove_mc(); + remove_tickets(); + remove_sdql2(); }); Byond.subscribeTo("update_listedturf", function (TC) { - turfcontents = TC; - if (current_tab == turfname) { - draw_listedturf(); - } + turfcontents = TC; + if (current_tab == turfname) { + draw_listedturf(); + } }); Byond.subscribeTo("update_misc", function (payload) { - let TN = payload.TN; - let TC = payload.TC; - misc.set(TN, TC); - if (current_tab == TN) { - draw_misc(TN); - } + let TN = payload.TN; + let TC = payload.TC; + misc.set(TN, TC); + if (current_tab == TN) { + draw_misc(TN); + } }); Byond.subscribeTo("update_split_admin_tabs", function (status) { - status = status == true; + status = status == true; - if (split_admin_tabs !== status) { - if (split_admin_tabs === true) { - removeStatusTab("Events"); - removeStatusTab("Fun"); - removeStatusTab("Game"); - } - update_verbs(); - } - split_admin_tabs = status; + if (split_admin_tabs !== status) { + if (split_admin_tabs === true) { + removeStatusTab("Events"); + removeStatusTab("Fun"); + removeStatusTab("Game"); + } + update_verbs(); + } + split_admin_tabs = status; }); Byond.subscribeTo("add_admin_tabs", function (ht) { - href_token = ht; - addPermanentTab("MC"); - addPermanentTab("Tickets"); + href_token = ht; + addPermanentTab("MC"); + addPermanentTab("Tickets"); }); Byond.subscribeTo("add_tickets_tabs", function (ht) { - href_token = ht; - addPermanentTab("Tickets"); + href_token = ht; + addPermanentTab("Tickets"); }); Byond.subscribeTo("update_examine", function (payload) { - examine = payload.EX; - if (examine.length > 0 && !verb_tabs.includes("Examine")) { - verb_tabs.push("Examine"); - addPermanentTab("Examine"); - } - if (current_tab == "Examine") { - draw_examine(); - } - if (payload.UPD) { - tab_change("Examine"); - } + examine = payload.EX; + if (examine.length > 0 && !verb_tabs.includes("Examine")) { + verb_tabs.push("Examine"); + addPermanentTab("Examine"); + } + if (current_tab == "Examine") { + draw_examine(); + } + if (payload.UPD) { + tab_change("Examine"); + } }); Byond.subscribeTo("update_sdql2", function (S) { - sdql2 = S; - if (sdql2.length > 0 && !verb_tabs.includes("SDQL2")) { - verb_tabs.push("SDQL2"); - addPermanentTab("SDQL2"); - } - if (current_tab == "SDQL2") { - draw_sdql2(); - } + sdql2 = S; + if (sdql2.length > 0 && !verb_tabs.includes("SDQL2")) { + verb_tabs.push("SDQL2"); + addPermanentTab("SDQL2"); + } + if (current_tab == "SDQL2") { + draw_sdql2(); + } }); Byond.subscribeTo("update_tickets", function (T) { - tickets = T; - if (!verb_tabs.includes("Tickets")) { - verb_tabs.push("Tickets"); - addPermanentTab("Tickets"); - } - if (current_tab == "Tickets") { - draw_tickets(); - } + tickets = T; + if (!verb_tabs.includes("Tickets")) { + verb_tabs.push("Tickets"); + addPermanentTab("Tickets"); + } + if (current_tab == "Tickets") { + draw_tickets(); + } }); Byond.subscribeTo("remove_listedturf", remove_listedturf); diff --git a/html/typing_indicator.html b/html/typing_indicator.html index 2988edff55f..18b69a0016d 100644 --- a/html/typing_indicator.html +++ b/html/typing_indicator.html @@ -1,46 +1,48 @@ - + - - - - - - + window.location = + "byond://?commandbar_typing=1&verb=" + + encodeURIComponent(verb) + + "&argument_length=" + + argument_length; + } + setTimeout(getoutput, 2000); + + diff --git a/icons/goonstation/LICENSE.md b/icons/goonstation/LICENSE.md index bb6102702e6..19e666c21c2 100644 --- a/icons/goonstation/LICENSE.md +++ b/icons/goonstation/LICENSE.md @@ -1,2 +1,2 @@ All files located in this directory and any subdirectories are licensed under the -Creative Commons 3.0 BY-NC-SA license (https://creativecommons.org/licenses/by-nc-sa/3.0) \ No newline at end of file +Creative Commons 3.0 BY-NC-SA license (https://creativecommons.org/licenses/by-nc-sa/3.0) diff --git a/icons/mob/animal_vr.dmi b/icons/mob/animal_vr.dmi index 75edbf26294..da182458ccc 100644 Binary files a/icons/mob/animal_vr.dmi and b/icons/mob/animal_vr.dmi differ diff --git a/ingame_manuals/malf_ai.html b/ingame_manuals/malf_ai.html index ff44c57e767..f6bcc569703 100644 --- a/ingame_manuals/malf_ai.html +++ b/ingame_manuals/malf_ai.html @@ -1,22 +1,68 @@ -

Malfunctioning AI guide


+

Malfunctioning AI guide

+
-This guide contains most important OOC information for malfunctioning AIs.
+This guide contains most important OOC information for malfunctioning AIs.
-

Goal


-As malfunctioning AI, your primary goal is to overtake station's systems. To do this, use software "Basic Encryption Hack" on APCs (right click on APC and select Basic Encryption Hack). Please note that hacked APCs have distinctive blue error screen, that tends to attract attention. Remember that malfunctioning AI is antagonist, so read server rules for antagonists. While hacking APCs is your official goal, feel free to create custom goal, as long as it is fun for everyone.
+

Goal

+
+As malfunctioning AI, your primary goal is to overtake station's systems. To do +this, use software "Basic Encryption Hack" on APCs (right click on APC and +select Basic Encryption Hack). Please note that hacked APCs have distinctive +blue error screen, that tends to attract attention. Remember that malfunctioning +AI is antagonist, so read server rules for antagonists. While hacking APCs is +your official goal, feel free to create custom goal, as long as it is fun for +everyone.
-

Hardware


-As malfunctioning AI, you may select one hardware piece to help you. Remember that once you select hardware piece, you cannot select another one, so choose wisely! Hardware may be selected by clicking "Select Hardware" button in Hardware tab. Following is list of possible hardware pieces:
-APU Generator - Auxiliary Power Unit which allows you to operate even without external power. However, running on APU will stop your CPU time generation, and temporarily disable most of your abilities. APU is also somewhat vulnerable to physical damage, and will fail if your core hardware integrity drops below 50%.
-Turrets Focus Enhancer - Removes safeties on installed turrets, boosting their rate of fire, health and enabling nano-regeneration module. This however increases power usage considerably, especially when regenerating damage.
-Secondary Processor Unit - Simple upgrade that increases your CPU time generation by 50%. Useful if you need to speed up your research.
-Secondary Memory Bank - Doubles amount of maximal CPU time you may store. This is useful if you need to use lots of abilities in short amount of time.
-Self-Destruct Explosives - Large blocks of C4 are attached to your physical core. This C4 has 15 second timer, and may be activated by special button that appears in your Hardware tab. This self-destruct will remain active, even if you are destroyed. If timer reaches 0 your core explodes in strong explosion. Obviously, this destroys you, as well as anyone nearby.
+

Hardware

+
+As malfunctioning AI, you may select one hardware piece to help you. Remember +that once you select hardware piece, you cannot select another one, so choose +wisely! Hardware may be selected by clicking "Select Hardware" button in +Hardware tab. Following is list of possible hardware pieces:
+APU Generator - Auxiliary Power Unit which allows you to operate even +without external power. However, running on APU will stop your CPU time +generation, and temporarily disable most of your abilities. APU is also somewhat +vulnerable to physical damage, and will fail if your core hardware integrity +drops below 50%.
+Turrets Focus Enhancer - Removes safeties on installed turrets, boosting +their rate of fire, health and enabling nano-regeneration module. This however +increases power usage considerably, especially when regenerating damage.
+Secondary Processor Unit - Simple upgrade that increases your CPU time +generation by 50%. Useful if you need to speed up your research.
+Secondary Memory Bank - Doubles amount of maximal CPU time you may store. +This is useful if you need to use lots of abilities in short amount of time.
+Self-Destruct Explosives - Large blocks of C4 are attached to your +physical core. This C4 has 15 second timer, and may be activated by special +button that appears in your Hardware tab. This self-destruct will remain active, +even if you are destroyed. If timer reaches 0 your core explodes in strong +explosion. Obviously, this destroys you, as well as anyone nearby.
-

Software


-Software are abilities that have to be unlocked via research menu (Hardware tab). Unlocked abilities appear in Software tab. Sometimes, abilities won't appear in this tab after being researched. This can be fixed by relogging or using "ai-core" command. Abilities are tiered, T1 being the weakest ones, while T4 are strongest ones. To reach higher tier you have to research abilities in lower tier. We currently have 12 abilities, in 3 research trees:
-Networking - Hacking-oriented abilities. T1 ability is Basic Encryption Hack, which allows you to hack more APCs. Higher tiers allow faking centcom messages, and even setting alert level. T4 ability is System Override, that rapidly hacks remaining APCs and gives you access to station self destruct sequence.
-Interdiction - Sabotage-oriented abilities. T1 ability allows you to recall emergency shuttle. Higher level abilities allow you to unlock cyborgs even without access to robotics console, and T4 ability allows you to hack other AIs to slave them under your control.
-Manipulation - Physical-oriented abilities. T1 ability allows you to break few lights, and rarely even APCs. T2 ability allows you to apply upgrade of your choice to camera, or reactivate broken camera. T3 ability allows you to create weak forcefield, that holds air, but won't last for long. And T4 ability allows you to overload machines, detonating them in weak explosion.
-

End


-If you still have some questions, either check the wiki, ask on IRC, or adminhelp and ask your friendly administration staff. +

Software

+
+Software are abilities that have to be unlocked via research menu (Hardware +tab). Unlocked abilities appear in Software tab. +Sometimes, abilities won't appear in this tab after being researched. This + can be fixed by relogging or using "ai-core" command. +Abilities are tiered, T1 being the weakest ones, while T4 are strongest ones. To +reach higher tier you have to research abilities in lower tier. We currently +have 12 abilities, in 3 research trees:
+Networking - Hacking-oriented abilities. T1 ability is Basic Encryption +Hack, which allows you to hack more APCs. Higher tiers allow faking centcom +messages, and even setting alert level. T4 ability is System Override, that +rapidly hacks remaining APCs and gives you access to station self destruct +sequence.
+Interdiction - Sabotage-oriented abilities. T1 ability allows you to +recall emergency shuttle. Higher level abilities allow you to unlock cyborgs +even without access to robotics console, and T4 ability allows you to hack other +AIs to slave them under your control.
+Manipulation - Physical-oriented abilities. T1 ability allows you to +break few lights, and rarely even APCs. T2 ability allows you to apply upgrade +of your choice to camera, or reactivate broken camera. T3 ability allows you to +create weak forcefield, that holds air, but won't last for long. And T4 ability +allows you to overload machines, detonating them in weak explosion.
+

End

+
+If you still have some questions, either check the wiki, ask on IRC, or +adminhelp and ask your friendly administration staff. diff --git a/interface/fonts/fonts.css b/interface/fonts/fonts.css index 8fbec5b88aa..c3fc05535d6 100644 --- a/interface/fonts/fonts.css +++ b/interface/fonts/fonts.css @@ -3,37 +3,37 @@ */ @font-face { - font-family: 'Grand9K Pixel'; + font-family: "Grand9K Pixel"; src: url(Grand9K_Pixel.ttf); } .font-grand9k_pixel { - font-family: 'Grand9K Pixel'; + font-family: "Grand9K Pixel"; } @font-face { - font-family: 'Pixellari'; + font-family: "Pixellari"; src: url(Pixellari.ttf); } .font-pixellari { - font-family: 'Pixellari'; + font-family: "Pixellari"; } @font-face { - font-family: 'TinyUnicode'; + font-family: "TinyUnicode"; src: url(TinyUnicode.ttf); } .font-tinyunicode { - font-family: 'TinyUnicode'; + font-family: "TinyUnicode"; } @font-face { - font-family: 'VCR OSD Mono'; + font-family: "VCR OSD Mono"; src: url(VCR_OSD_Mono.ttf); } .font-vcr_osd_mono { - font-family: 'VCR OSD Mono'; + font-family: "VCR OSD Mono"; } diff --git a/maps/_templates_and_guidance/Mapping Templates Readme.md b/maps/_templates_and_guidance/Mapping Templates Readme.md index 124c24eece3..13d7c84ab6b 100644 --- a/maps/_templates_and_guidance/Mapping Templates Readme.md +++ b/maps/_templates_and_guidance/Mapping Templates Readme.md @@ -4,14 +4,12 @@ The intent of this file is to allow you to more easily be able to follow mapping The following folders will be listed here. If there’s been an update and this readme.md is out of date, let a maintainer on your codebase know. For CHOMPStation, this is a staffdev/maintainer, for VOREStation, this is a maintainer, for Polaris, this is also the maintainer role. - - -* Additional folders TBD. -* Mapping Guides - * This folder exists for newer contributors to physically pull examples from, for example; SMES Wiring.dmm would be for guidance on how to properly wire an SMES. This is not an exhaustive list, but should help the repeated/FAQ questions by allowing one to poke at it in a map editor. -* Public Event Templates - * This folder exists to house templates available to the public. Bear in mind that Event Manager staff will likely not house all event templates publicly for security + future events, but this should be updated once a map is done with or an EM leaves the team and wishes to leave their maps public for future use. -* Public Ship Templates - * This folder exists for SHIP templates that do not normally go into the ships folder (For reference, this ship folder is maps/offmap_vr/om_ships, or overmap/ships). This is for example ships, or for EM-specific, public ships. -* Templates - * This folder is specifically for pre-prepared, ready-to-place templates for things such as drop pods, small maps, etc, things EM-staff will use regularly that are not necessarily related to events. +- Additional folders TBD. +- Mapping Guides + - This folder exists for newer contributors to physically pull examples from, for example; SMES Wiring.dmm would be for guidance on how to properly wire an SMES. This is not an exhaustive list, but should help the repeated/FAQ questions by allowing one to poke at it in a map editor. +- Public Event Templates + - This folder exists to house templates available to the public. Bear in mind that Event Manager staff will likely not house all event templates publicly for security + future events, but this should be updated once a map is done with or an EM leaves the team and wishes to leave their maps public for future use. +- Public Ship Templates + - This folder exists for SHIP templates that do not normally go into the ships folder (For reference, this ship folder is maps/offmap_vr/om_ships, or overmap/ships). This is for example ships, or for EM-specific, public ships. +- Templates + - This folder is specifically for pre-prepared, ready-to-place templates for things such as drop pods, small maps, etc, things EM-staff will use regularly that are not necessarily related to events. diff --git a/maps/tether/submaps/submaps_readme.md b/maps/tether/submaps/submaps_readme.md index 2eddf761f50..79dbaed151f 100644 --- a/maps/tether/submaps/submaps_readme.md +++ b/maps/tether/submaps/submaps_readme.md @@ -2,4 +2,4 @@ DO NOT PUT EXPEDITION SUBMAPS HERE. Only submaps and areas EXCLUSIVE to the Tether go here. Underdark POIs are here because they use Virgo3b turfs EXCLUSIVE to Tether. -If you're unsure, ask in #dev-general. \ No newline at end of file +If you're unsure, ask in #dev-general. diff --git a/news_articles/space_magazine_1.html b/news_articles/space_magazine_1.html index dbdd3f43ed6..1287fa48d4e 100644 --- a/news_articles/space_magazine_1.html +++ b/news_articles/space_magazine_1.html @@ -1,135 +1,197 @@ - +

+

- -

Welcome to SPACE Magazine

-
-
+

Welcome to SPACE Magazine

+
+

- SPACE Magazine is a new force in Journalism in the 26th Century- bringing news and information to the multitudes of Star Systems settled by Sentient Life, - letting everyone know whats happening across the Stars, millions of miles away. News if first and foremost our forte, but articles over important - individuals and new developments will also be here in the magazine, which we shall ship out every month with a new issue. This, is our very first issue, - and we hope to continue for many years to come. + SPACE Magazine is a new force in Journalism in the 26th Century- bringing news + and information to the multitudes of Star Systems settled by Sentient Life, + letting everyone know what's happening across the Stars, millions of miles + away. News if first and foremost our forte, but articles over important + individuals and new developments will also be here in the magazine, which we + shall ship out every month with a new issue. This, is our very first issue, + and we hope to continue for many years to come.

- In this first issue, we will address a few incidents that have come up as of recent days- a attempted, but disastrous attack by Pirates against the colony - of Onaios Prime, thwarted by the latest in weapons technology. A meteor shower that rained disaster on the colonial world of Brinkburn in the lucrative - system of Nyx, causing many citizens to leave the planet. An attack by terrorists on the colony of Asilliss VII, resulting in many deaths, and the Great - Carp Migrations that have been occurring in recent days in the Nyx System. + In this first issue, we will address a few incidents that have come up as of + recent days- a attempted, but disastrous attack by Pirates against the colony + of Onaios Prime, thwarted by the latest in weapons technology. A meteor shower + that rained disaster on the colonial world of Brinkburn in the lucrative + system of Nyx, causing many citizens to leave the planet. An attack by + terrorists on the colony of Asilliss VII, resulting in many deaths, and the + Great Carp Migrations that have been occurring in recent days in the Nyx + System.

- -

+

Pirates Underestimate Colonial Defenses

-
+

- This week, a pirate group that has stolen a SolGov Battlecruiser has attempted to commit a raid with it upon a colony world Onaios Prime, in the Onaios - system. However, it was quickly eradicated along with its escort by a planetside battery of Mass Drivers produced recently by Dawnlight Celestial Defence. - After this incident Dawnlight has registered an influx of demand from other colonies, as their weapons are relatively affordable, registering slight growth - in stock ratings for the first time in 250 years, when the success of Dawnlight even competed with corporations like Hephaestus. We have found a written - account of one of the writers of local news agency, and with their permission are including it in this article. + This week, a pirate group that has stolen a SolGov Battlecruiser has attempted + to commit a raid with it upon a colony world Onaios Prime, in the Onaios + system. However, it was quickly eradicated along with its escort by a + planetside battery of Mass Drivers produced recently by Dawnlight Celestial + Defence. After this incident Dawnlight has registered an influx of demand from + other colonies, as their weapons are relatively affordable, registering slight + growth in stock ratings for the first time in 250 years, when the success of + Dawnlight even competed with corporations like Hephaestus. We have found a + written account of one of the writers of local news agency, and with their + permission are including it in this article.

- It was almost midnight when I was driving around the AURA 2, a new anti-orbital installation, on my way home from my office, after some overtime. I have - heard of its construction project and have never paid much attention to it, the world of Onaios Prime that I live on has always been only moderately - wealthy, and peaceful... until last night. A loud siren played from the complex's direction, breaking the silence of the night. I stopped my vehicle where - an overhang down to the valley let me look at the platform, from 50 meters above it, and about 300 meters away from it, and I saw it for my first time. + It was almost midnight when I was driving around the AURA 2, a new + anti-orbital installation, on my way home from my office, after some overtime. + I have heard of its construction project and have never paid much attention to + it, the world of Onaios Prime that I live on has always been only moderately + wealthy, and peaceful... until last night. A loud siren played from the + complex's direction, breaking the silence of the night. I stopped my vehicle + where an overhang down to the valley let me look at the platform, from 50 + meters above it, and about 300 meters away from it, and I saw it for my first + time.

- A great bunker in the middle was having its windows shut in blast doors, shying away from the reason this is an anti-orbital installation: The jeeps and - trucks that were scurrying to hide in the bunker were but the tiniest little dot, compared to the massive Mass Drivers, that slowly, but so steadily, with - a bass, gentle hum, began towering to the sky, reaching out to it with a barrel so long you would need two loaded semi-trucks to cover the length. The - barrels aligned, and I could still hear the humming, but it started growing stronger, stronger... before one of the barrels sparked inside a few times, and - I was blinded by a vast flash... Only then, the humming cut off, only then, I heard the lightning, and only then, a spiking, overwhelming pitch of - capacitor discharge plummeted to my eardrums, only to be followed by an encroaching thunder of a blastwave, shunting masses of air against me. + A great bunker in the middle was having its windows shut in blast doors, + shying away from the reason this is an anti-orbital installation: The jeeps + and trucks that were scurrying to hide in the bunker were but the tiniest + little dot, compared to the massive Mass Drivers, that slowly, but so + steadily, with a bass, gentle hum, began towering to the sky, reaching out to + it with a barrel so long you would need two loaded semi-trucks to cover the + length. The barrels aligned, and I could still hear the humming, but it + started growing stronger, stronger... before one of the barrels sparked inside + a few times, and I was blinded by a vast flash... Only then, the humming cut + off, only then, I heard the lightning, and only then, a spiking, overwhelming + pitch of capacitor discharge plummeted to my eardrums, only to be followed by + an encroaching thunder of a blastwave, shunting masses of air against me.

- Only after a few seconds, I regained my hearing and sight to feel the echoes of the blast, and to see another Mass Driver was discharging, sparking. I - covered the sight of it in time, to see the entire valley was lit for a split second as well as the sun could do, and I heard the discharge again, and I - heard its calling. Every spike, a declaration of freedom. Every thunderblast, a declaration of sovereignty. The Mass Drivers would flash, marking dawn upon - the invaders to signal the humanity made its stand here, and it shall persevere. The warhead that it would expel was our fist that would smite them from - our sky. I did not know who have we fought against at that time, but at that moment, and ever since, I never looked at the night sky the same way again. I - believe that that sky is our home. -Written by Liun Asitero, Onaios Daily + Only after a few seconds, I regained my hearing and sight to feel the echoes + of the blast, and to see another Mass Driver was discharging, sparking. I + covered the sight of it in time, to see the entire valley was lit for a split + second as well as the sun could do, and I heard the discharge again, and I + heard its calling. Every spike, a declaration of freedom. Every thunderblast, + a declaration of sovereignty. The Mass Drivers would flash, marking dawn upon + the invaders to signal the humanity made its stand here, and it shall + persevere. The warhead that it would expel was our fist that would smite them + from our sky. I did not know who have we fought against at that time, but at + that moment, and ever since, I never looked at the night sky the same way + again. I believe that that sky is our home. -Written by Liun Asitero, Onaios + Daily

Written by Lucas Shiito - -

-

Brinkburn Refugees and Sapients Rights

-
+

+

Brinkburn Refugees and Sapient's Rights

+

- One of Nyx's planets, Brinkburn, has had a catastrophe happen in form of a meteor storm three days ago. Nyx has lashed out with a solar corona that, while - having a miniscule effect on traffic and stations, has managed to deflect several asteroids from the belt natively present around Brinkburn. This caused - massive, unsustainable damage to the habitation complexes present on the planet that are occupied by several hundreds of settlers, and given their scarce - material stocks, they had no other choice but to escape, to find another place to survive in. + One of Nyx's planets, Brinkburn, has had a catastrophe happen in form of a + meteor storm three days ago. Nyx has lashed out with a solar corona that, + while having a miniscule effect on traffic and stations, has managed to + deflect several asteroids from the belt natively present around Brinkburn. + This caused massive, unsustainable damage to the habitation complexes present + on the planet that are occupied by several hundreds of settlers, and given + their scarce material stocks, they had no other choice but to escape, to find + another place to survive in.

- The situation was further complicated by the very asteroid rings that have started this misfortune; the refugees did not have sufficiently advanced - navigation computers on their pods to steer them safely through the rings. Approximately 20% of population is estimated to have not made it through. The - shuttles that have shipped the settlers on the world in the first place needed to be dismantled and used for scrap to expand the living area, and the more - advanced components were used to wrangle the escape pods together. + The situation was further complicated by the very asteroid rings that have + started this misfortune; the refugees did not have sufficiently advanced + navigation computers on their pods to steer them safely through the rings. + Approximately 20% of population is estimated to have not made it through. The + shuttles that have shipped the settlers on the world in the first place needed + to be dismantled and used for scrap to expand the living area, and the more + advanced components were used to wrangle the escape pods together.

- Most of the refugees have found their way to Emerald Habitation, a station in Nyx. The station already has issues with over-population and air - purification, and the sudden influx of human settlers has introduced even more problems. Firstly, it has made it much harder to process travelers passing - through, making travel in Nyx either very dangerous through Void Star, or very expensive through NAS Crescent. Secondly, Emerald Habitation has been - housing a large number of Unathi, which have been harassing the refugees, some of them are even a part of the station's security, making appeals to them - only worsen the situation. + Most of the refugees have found their way to Emerald Habitation, a station in + Nyx. The station already has issues with over-population and air purification, + and the sudden influx of human settlers has introduced even more problems. + Firstly, it has made it much harder to process travelers passing through, + making travel in Nyx either very dangerous through Void Star, or very + expensive through NAS Crescent. Secondly, Emerald Habitation has been housing + a large number of Unathi, which have been harassing the refugees, some of them + are even a part of the station's security, making appeals to them only worsen + the situation.

- We can only hope a new home will be found and built for the poor refugees, and that the Skrell present on station, that are keeping the situation - relatively free of casualties, continue to sustain a safe, if not non-hostile environment on the overpopulated station. + We can only hope a new home will be found and built for the poor refugees, and + that the Skrell present on station, that are keeping the situation relatively + free of casualties, continue to sustain a safe, if not non-hostile environment + on the overpopulated station.

Written by Laura Hunton - -

+

Terror Attack on Asilliss VII

-
+

- Planet Asilliss VI has been a civil uprising hotspot for a few weeks now, and things have recently yet again escalated. A research facility belonging to - NanoTrasen, one of several to be specific, that specializes on an undisclosed project, has been attacked by a group of masked raiders armed with automatic - weapons, using several buggies for transport. Two hours after the incident, Asilliss Liberation Force claimed responsibility. "Companies like NanoTrasen - are advancing us, but into slavery and containment! Their technology only brings control to the corrupt over the honest people of Asilliss! We cannot stand - idle! Join us and befall those who take our lives from our control!", claimed a man hiding in a shade on video that was sent to a local entertainment - station to be broadcasted under threat of attack. + Planet Asilliss VI has been a civil uprising hotspot for a few weeks now, and + things have recently yet again escalated. A research facility belonging to + NanoTrasen, one of several to be specific, that specializes on an undisclosed + project, has been attacked by a group of masked raiders armed with automatic + weapons, using several buggies for transport. Two hours after the incident, + Asilliss Liberation Force claimed responsibility. "Companies like NanoTrasen + are advancing us, but into slavery and containment! Their technology only + brings control to the corrupt over the honest people of Asilliss! We cannot + stand idle! Join us and befall those who take our lives from our control!", + claimed a man hiding in a shade on video that was sent to a local + entertainment station to be broadcasted under threat of attack.

- Up until now, the government's militia has been relatively ineffective at quelling this terrorist cell, while their statistics register a number of arrests - and casualties, the group is still registering influx of recruits. However, NanoTrasen seems to have been highly impacted by this attack, judging from - press release of NanoTrasen, Nyx Division: "As a company, we must maintain our safety standard for our employees, as well as secure our installations. The - continued unrest on Asilliss that is resulting in loss of investments is forcing our hand to resort to particularly prejudicial measures and we are - arranging cooperation with the governmental forces." + Up until now, the government's militia has been relatively ineffective at + quelling this terrorist cell, while their statistics register a number of + arrests and casualties, the group is still registering influx of recruits. + However, NanoTrasen seems to have been highly impacted by this attack, judging + from press release of NanoTrasen, Nyx Division: "As a company, we must + maintain our safety standard for our employees, as well as secure our + installations. The continued unrest on Asilliss that is resulting in loss of + investments is forcing our hand to resort to particularly prejudicial measures + and we are arranging cooperation with the governmental forces."

- We have information from a trusted source, who we shall allow to remain unnamed, that NanoTrasen is arranging a loan to Asiliss in form of acquisition of a - small number of vehicles from Terraphistus Military Armor and small arms shipped all the way from Mars Security Industries, as well as hiring services from - a newly instated PMC, SAARE, to protect other NanoTrasen's installations. We have very little information on SAARE due to its novelty, except that it has - accepted several decorated veterans from various security forces and armies, and specializes on top secret operations. Only time will tell if these - measures shall be taken and how shall they affect the unrest on Asilliss IV, but be sure that we shall provide our readers with full coverage! + We have information from a trusted source, who we shall allow to remain + unnamed, that NanoTrasen is arranging a loan to Asiliss in form of acquisition + of a small number of vehicles from Terraphistus Military Armor and small arms + shipped all the way from Mars Security Industries, as well as hiring services + from a newly instated PMC, SAARE, to protect other NanoTrasen's installations. + We have very little information on SAARE due to its novelty, except that it + has accepted several decorated veterans from various security forces and + armies, and specializes on top secret operations. Only time will tell if these + measures shall be taken and how shall they affect the unrest on Asilliss IV, + but be sure that we shall provide our readers with full coverage!

Written by Johnathan Townsend - -

+

The Great Carp Migration

-
+

- Carp and Pike have plagued space station windows and ship paint jobs for the past hundred years, and while local businesses make money off of eradicating - them by the hundreds, they only seem to increase in number and size. Xenobiologists at Brickburn have come to the conclusion that that these pests most - likely came from Erebus. "Was really hard to figure out at first," says researcher Gregory Hills, "They really like to, you know, bite things. But once we - got a few hundred tagged ones out there the answer became pretty obvious." He went further on to explain that through their research they've created a - basic carp life cycle, starting at the center of the gas giant and ending in the upper atmosphere, "They tend to die there.", he remarks, "Carp don't - really survive in space unless they are really, really big. Hence why we get so many." When asked why the carp come to space in the first place, he shrugs, - "We don't really know. We think maybe they can sense the stations up there somehow and are looking for food." + Carp and Pike have plagued space station windows and ship paint jobs for the + past hundred years, and while local businesses make money off of eradicating + them by the hundreds, they only seem to increase in number and size. + Xenobiologists at Brickburn have come to the conclusion that that these pests + most likely came from Erebus. "Was really hard to figure out at first," says + researcher Gregory Hills, "They really like to, you know, bite things. But + once we got a few hundred tagged ones out there the answer became pretty + obvious." He went further on to explain that through their research they've + created a basic carp life cycle, starting at the center of the gas giant and + ending in the upper atmosphere, "They tend to die there.", he remarks, "Carp + don't really survive in space unless they are really, really big. Hence why we + get so many." When asked why the carp come to space in the first place, he + shrugs, "We don't really know. We think maybe they can sense the stations up + there somehow and are looking for food."

- Sadly this does not help much in protecting the citizens of the stars from the dreadful beasts. In the last month, there have been a reported 37 deaths due - to Carp and Pike related incidents, making the Erebus Beasts a serious threat to people thinking of working on a station. Scientists believe that at some - point this year, stations and ships in the Nyx System will be subjected to the largest migration of Carp and Pike that has ever been seen, and it may cause - serious damage to interests in the system. + Sadly this does not help much in protecting the citizens of the stars from the + dreadful beasts. In the last month, there have been a reported 37 deaths due + to Carp and Pike related incidents, making the Erebus Beasts a serious threat + to people thinking of working on a station. Scientists believe that at some + point this year, stations and ships in the Nyx System will be subjected to the + largest migration of Carp and Pike that has ever been seen, and it may cause + serious damage to interests in the system.

-Written by Peggy Resaih \ No newline at end of file +Written by Peggy Re'saih diff --git a/package.json b/package.json new file mode 100644 index 00000000000..1d123f3ffce --- /dev/null +++ b/package.json @@ -0,0 +1,10 @@ +{ + "devDependencies": { + "@biomejs/biome": "^2.1.2", + "prettier": "^3.6.2" + }, + "scripts": { + "tgui:fix": "biome check --write --unsafe tgui", + "tgui:lint": "biome lint tgui" + } +} diff --git a/sound/goonstation/LICENSE.md b/sound/goonstation/LICENSE.md index bb6102702e6..19e666c21c2 100644 --- a/sound/goonstation/LICENSE.md +++ b/sound/goonstation/LICENSE.md @@ -1,2 +1,2 @@ All files located in this directory and any subdirectories are licensed under the -Creative Commons 3.0 BY-NC-SA license (https://creativecommons.org/licenses/by-nc-sa/3.0) \ No newline at end of file +Creative Commons 3.0 BY-NC-SA license (https://creativecommons.org/licenses/by-nc-sa/3.0) diff --git a/tgui/.eslintignore b/tgui/.eslintignore deleted file mode 100644 index 4f735f3c518..00000000000 --- a/tgui/.eslintignore +++ /dev/null @@ -1,17 +0,0 @@ -/.yarn/** -/**/node_modules -/**/*.bundle.* -/**/*.chunk.* -/**/*.hot-update.* -**.lock -**.log -**.json -**.svg -**.scss -**.md -**.css -**.txt -**.woff2 -**.eot -**.ttf -/public diff --git a/tgui/.eslintrc.yml b/tgui/.eslintrc.yml deleted file mode 100644 index 7ad819bc245..00000000000 --- a/tgui/.eslintrc.yml +++ /dev/null @@ -1,774 +0,0 @@ -root: true -extends: prettier -parser: '@typescript-eslint/parser' -parserOptions: - ecmaVersion: 2020 - sourceType: module - ecmaFeatures: - jsx: true -env: - es6: true - browser: true - node: true -plugins: - - react - - unused-imports - - simple-import-sort - - '@typescript-eslint' -settings: - react: - version: '19.1' -rules: - ## Possible Errors - ## ---------------------------------------- - ## Enforce “for” loop update clause moving the counter in the right - ## direction. - # for-direction: error - ## Enforce return statements in getters - # getter-return: error - ## Disallow using an async function as a Promise executor - no-async-promise-executor: error - ## Disallow await inside of loops - # no-await-in-loop: error - ## Disallow comparing against -0 - # no-compare-neg-zero: error - ## Disallow assignment operators in conditional expressions - no-cond-assign: error - ## Disallow the use of console - # no-console: error - ## Disallow constant expressions in conditions - # no-constant-condition: error - ## Disallow control characters in regular expressions - # no-control-regex: error - ## Disallow the use of debugger - no-debugger: error - ## Disallow duplicate arguments in function definitions - no-dupe-args: error - ## Disallow duplicate keys in object literals - no-dupe-keys: error - ## Disallow duplicate case labels - no-duplicate-case: error - ## Disallow empty block statements - # no-empty: error - ## Disallow empty character classes in regular expressions - no-empty-character-class: error - ## Disallow reassigning exceptions in catch clauses - no-ex-assign: error - ## Disallow unnecessary boolean casts - no-extra-boolean-cast: error - ## Disallow unnecessary parentheses - # no-extra-parens: warn - ## Disallow unnecessary semicolons - no-extra-semi: error - ## Disallow reassigning function declarations - no-func-assign: error - ## Disallow assigning to imported bindings - no-import-assign: error - ## Disallow variable or function declarations in nested blocks - no-inner-declarations: error - ## Disallow invalid regular expression strings in RegExp constructors - no-invalid-regexp: error - ## Disallow irregular whitespace - no-irregular-whitespace: error - ## Disallow characters which are made with multiple code points in character - ## class syntax - no-misleading-character-class: error - ## Disallow calling global object properties as functions - no-obj-calls: error - ## Disallow calling some Object.prototype methods directly on objects - no-prototype-builtins: error - ## Disallow multiple spaces in regular expressions - no-regex-spaces: error - ## Disallow sparse arrays - no-sparse-arrays: error - ## Disallow template literal placeholder syntax in regular strings - no-template-curly-in-string: error - ## Disallow confusing multiline expressions - no-unexpected-multiline: error - ## Disallow unreachable code after return, throw, continue, and break - ## statements - # no-unreachable: warn - ## Disallow control flow statements in finally blocks - no-unsafe-finally: error - ## Disallow negating the left operand of relational operators - no-unsafe-negation: error - ## Disallow assignments that can lead to race conditions due to usage of - ## await or yield - # require-atomic-updates: error - ## Require calls to isNaN() when checking for NaN - use-isnan: error - ## Enforce comparing typeof expressions against valid strings - valid-typeof: error - - ## Best practices - ## ---------------------------------------- - ## Enforce getter and setter pairs in objects and classes - # accessor-pairs: error - ## Enforce return statements in callbacks of array methods - # array-callback-return: error - ## Enforce the use of variables within the scope they are defined - # block-scoped-var: error - ## Enforce that class methods utilize this - # class-methods-use-this: error - ## Enforce a maximum cyclomatic complexity allowed in a program - complexity: [error, { max: 50 }] - ## Require return statements to either always or never specify values - # consistent-return: error - ## Enforce consistent brace style for all control statements - curly: [error, multi-line] - ## Require default cases in switch statements - # default-case: error - ## Enforce default parameters to be last - # default-param-last: error - ## Enforce consistent newlines before and after dots - dot-location: [error, property] - ## Enforce dot notation whenever possible - # dot-notation: error - ## Require the use of === and !== - eqeqeq: [error, always] - ## Require for-in loops to include an if statement - # guard-for-in: error - ## Enforce a maximum number of classes per file - # max-classes-per-file: error - ## Disallow the use of alert, confirm, and prompt - # no-alert: error - ## Disallow the use of arguments.caller or arguments.callee - # no-caller: error - ## Disallow lexical declarations in case clauses - no-case-declarations: error - ## Disallow division operators explicitly at the beginning of regular - ## expressions - # no-div-regex: error - ## Disallow else blocks after return statements in if statements - # no-else-return: error - ## Disallow empty functions - # no-empty-function: error - ## Disallow empty destructuring patterns - no-empty-pattern: error - ## Disallow null comparisons without type-checking operators - # no-eq-null: error - ## Disallow the use of eval() - # no-eval: error - ## Disallow extending native types - # no-extend-native: error - ## Disallow unnecessary calls to .bind() - # no-extra-bind: error - ## Disallow unnecessary labels - # no-extra-label: error - ## Disallow fallthrough of case statements - no-fallthrough: error - ## Disallow leading or trailing decimal points in numeric literals - # no-floating-decimal: error - ## Disallow assignments to native objects or read-only global variables - no-global-assign: error - ## Disallow shorthand type conversions - # no-implicit-coercion: error - ## Disallow variable and function declarations in the global scope - # no-implicit-globals: error - ## Disallow the use of eval()-like methods - # no-implied-eval: error - ## Disallow this keywords outside of classes or class-like objects - # no-invalid-this: error - ## Disallow the use of the __iterator__ property - # no-iterator: error - ## Disallow labeled statements - # no-labels: error - ## Disallow unnecessary nested blocks - # no-lone-blocks: error - ## Disallow function declarations that contain unsafe references inside - ## loop statements - # no-loop-func: error - ## Disallow magic numbers - # no-magic-numbers: error - ## Disallow multiple spaces - no-multi-spaces: warn - ## Disallow multiline strings - # no-multi-str: error - ## Disallow new operators outside of assignments or comparisons - # no-new: error - ## Disallow new operators with the Function object - # no-new-func: error - ## Disallow new operators with the String, Number, and Boolean objects - # no-new-wrappers: error - ## Disallow octal literals - no-octal: error - ## Disallow octal escape sequences in string literals - no-octal-escape: error - ## Disallow reassigning function parameters - # no-param-reassign: error - ## Disallow the use of the __proto__ property - # no-proto: error - ## Disallow variable redeclaration - no-redeclare: error - ## Disallow certain properties on certain objects - # no-restricted-properties: error - ## Disallow assignment operators in return statements - no-return-assign: error - ## Disallow unnecessary return await - # no-return-await: error - ## Disallow javascript: urls - # no-script-url: error - ## Disallow assignments where both sides are exactly the same - no-self-assign: error - ## Disallow comparisons where both sides are exactly the same - # no-self-compare: error - ## Disallow comma operators - no-sequences: error - ## Disallow throwing literals as exceptions - # no-throw-literal: error - ## Disallow unmodified loop conditions - # no-unmodified-loop-condition: error - ## Disallow unused expressions - # no-unused-expressions: error - ## Disallow unused labels - no-unused-labels: warn - ## Disallow unnecessary calls to .call() and .apply() - # no-useless-call: error - ## Disallow unnecessary catch clauses - # no-useless-catch: error - ## Disallow unnecessary concatenation of literals or template literals - # no-useless-concat: error - ## Disallow unnecessary escape characters - no-useless-escape: warn - ## Disallow redundant return statements - # no-useless-return: error - ## Disallow void operators - # no-void: error - ## Disallow specified warning terms in comments - # no-warning-comments: error - ## Disallow with statements - no-with: error - ## Enforce using named capture group in regular expression - # prefer-named-capture-group: error - ## Require using Error objects as Promise rejection reasons - # prefer-promise-reject-errors: error - ## Disallow use of the RegExp constructor in favor of regular expression - ## literals - # prefer-regex-literals: error - ## Enforce the consistent use of the radix argument when using parseInt() - radix: error - ## Disallow async functions which have no await expression - # require-await: error - ## Enforce the use of u flag on RegExp - # require-unicode-regexp: error - ## Require var declarations be placed at the top of their containing scope - # vars-on-top: error - ## Require parentheses around immediate function invocations - # wrap-iife: error - ## Require or disallow “Yoda” conditions - # yoda: error - - ## Strict mode - ## ---------------------------------------- - ## Require or disallow strict mode directives - strict: error - - ## Variables - ## ---------------------------------------- - ## Require or disallow initialization in variable declarations - # init-declarations: error - ## Disallow deleting variables - no-delete-var: error - ## Disallow labels that share a name with a variable - # no-label-var: error - ## Disallow specified global variables - # no-restricted-globals: error - ## Disallow variable declarations from shadowing variables declared in - ## the outer scope - # no-shadow: error - ## Disallow identifiers from shadowing restricted names - no-shadow-restricted-names: error - ## Disallow the use of undeclared variables unless mentioned - ## in /*global*/ comments - ## NOTE: Pointless when TypeScript can check for this - # no-undef: error - ## Disallow initializing variables to undefined - no-undef-init: error - ## Disallow the use of undefined as an identifier - # no-undefined: error - ## Disallow unused variables - # no-unused-vars: error - ## Disallow the use of variables before they are defined - # no-use-before-define: error - - ## Code style - ## ---------------------------------------- - ## Enforce linebreaks after opening and before closing array brackets - array-bracket-newline: [error, consistent] - ## Enforce consistent spacing inside array brackets - array-bracket-spacing: [error, never] - ## Enforce line breaks after each array element - # array-element-newline: error - ## Disallow or enforce spaces inside of blocks after opening block and - ## before closing block - block-spacing: [error, always] - ## Enforce consistent brace style for blocks - # brace-style: [error, stroustrup, { allowSingleLine: false }] - ## Enforce camelcase naming convention - # camelcase: error - ## Enforce or disallow capitalization of the first letter of a comment - # capitalized-comments: error - ## Require or disallow trailing commas - comma-dangle: [ - error, - { - arrays: always-multiline, - objects: always-multiline, - imports: always-multiline, - exports: always-multiline, - functions: only-multiline, ## Optional on functions - }, - ] - ## Enforce consistent spacing before and after commas - comma-spacing: [error, { before: false, after: true }] - ## Enforce consistent comma style - comma-style: [error, last] - ## Enforce consistent spacing inside computed property brackets - computed-property-spacing: [error, never] - ## Enforce consistent naming when capturing the current execution context - # consistent-this: error - ## Require or disallow newline at the end of files - # eol-last: error - ## Require or disallow spacing between function identifiers and their - ## invocations - func-call-spacing: [error, never] - ## Require function names to match the name of the variable or property - ## to which they are assigned - # func-name-matching: error - ## Require or disallow named function expressions - # func-names: error - ## Enforce the consistent use of either function declarations or expressions - # func-style: [error, expression] - ## Enforce line breaks between arguments of a function call - # function-call-argument-newline: error - ## Enforce consistent line breaks inside function parentheses - ## NOTE: This rule does not honor a newline on opening paren. - # function-paren-newline: [error, never] - ## Disallow specified identifiers - # id-blacklist: error - ## Enforce minimum and maximum identifier lengths - # id-length: error - ## Require identifiers to match a specified regular expression - # id-match: error - ## Enforce the location of arrow function bodies - # implicit-arrow-linebreak: error - ## Enforce consistent indentation - # indent: [error, 2, { SwitchCase: 1 }] - ## Enforce the consistent use of either double or single quotes in JSX - ## attributes - # jsx-quotes: [error, prefer-double] - ## Enforce consistent spacing between keys and values in object literal - ## properties - # key-spacing: [error, { beforeColon: false, afterColon: true }] - ## Enforce consistent spacing before and after keywords - # keyword-spacing: [error, { before: true, after: true }] - ## Enforce position of line comments - # line-comment-position: error - ## Enforce consistent linebreak style - # linebreak-style: error - ## Require empty lines around comments - # lines-around-comment: error - ## Require or disallow an empty line between class members - # lines-between-class-members: error - ## Enforce a maximum depth that blocks can be nested - # max-depth: error - ## Enforce a maximum line length - # max-len: [error, { - # code: 80, - # ## Ignore imports - # ignorePattern: '^(import\s.+\sfrom\s|.*require\()', - # ignoreUrls: true, - # ignoreRegExpLiterals: true, - # ignoreStrings: true, - # ignoreTemplateLiterals: true, - # }] - ## Enforce a maximum number of lines per file - # max-lines: error - ## Enforce a maximum number of line of code in a function - # max-lines-per-function: error - ## Enforce a maximum depth that callbacks can be nested - # max-nested-callbacks: error - ## Enforce a maximum number of parameters in function definitions - # max-params: error - ## Enforce a maximum number of statements allowed in function blocks - # max-statements: error - ## Enforce a maximum number of statements allowed per line - # max-statements-per-line: error - ## Enforce a particular style for multiline comments - # multiline-comment-style: error - ## Enforce newlines between operands of ternary expressions - # multiline-ternary: [error, always-multiline] - ## Require constructor names to begin with a capital letter - # new-cap: error - ## Enforce or disallow parentheses when invoking a constructor with no - ## arguments - # new-parens: error - ## Require a newline after each call in a method chain - # newline-per-chained-call: error - ## Disallow Array constructors - # no-array-constructor: error - ## Disallow bitwise operators - # no-bitwise: error - ## Disallow continue statements - # no-continue: error - ## Disallow inline comments after code - # no-inline-comments: error - ## Disallow if statements as the only statement in else blocks - # no-lonely-if: error - ## Disallow mixed binary operators - # no-mixed-operators: error - ## Disallow mixed spaces and tabs for indentation - # no-mixed-spaces-and-tabs: error - ## Disallow use of chained assignment expressions - # no-multi-assign: error - ## Disallow multiple empty lines - # no-multiple-empty-lines: error - ## Disallow negated conditions - # no-negated-condition: error - ## Disallow nested ternary expressions - # no-nested-ternary: error - ## Disallow Object constructors - # no-new-object: error - ## Disallow the unary operators ++ and -- - # no-plusplus: error - ## Disallow specified syntax - # no-restricted-syntax: error - ## Disallow all tabs - # no-tabs: error - ## Disallow ternary operators - # no-ternary: error - ## Disallow trailing whitespace at the end of lines - # no-trailing-spaces: error - ## Disallow dangling underscores in identifiers - # no-underscore-dangle: error - ## Disallow ternary operators when simpler alternatives exist - # no-unneeded-ternary: error - ## Disallow whitespace before properties - # no-whitespace-before-property: error - ## Enforce the location of single-line statements - # nonblock-statement-body-position: error - ## Enforce consistent line breaks inside braces - # object-curly-newline: [error, { multiline: true }] - ## Enforce consistent spacing inside braces - object-curly-spacing: [error, always] - ## Enforce placing object properties on separate lines - # object-property-newline: error - ## Enforce variables to be declared either together or separately in - ## functions - # one-var: error - ## Require or disallow newlines around variable declarations - # one-var-declaration-per-line: error - ## Require or disallow assignment operator shorthand where possible - # operator-assignment: error - ## Enforce consistent linebreak style for operators - # operator-linebreak: [error, before] - ## Require or disallow padding within blocks - # padded-blocks: error - ## Require or disallow padding lines between statements - # padding-line-between-statements: error - ## Disallow using Object.assign with an object literal as the first - ## argument and prefer the use of object spread instead. - # prefer-object-spread: error - ## Require quotes around object literal property names - # quote-props: error - ## Enforce the consistent use of either backticks, double, or single quotes - # quotes: [error, single] - ## Require or disallow semicolons instead of ASI - semi: error - ## Enforce consistent spacing before and after semicolons - semi-spacing: [error, { before: false, after: true }] - ## Enforce location of semicolons - semi-style: [error, last] - ## Require object keys to be sorted - # sort-keys: error - ## Require variables within the same declaration block to be sorted - # sort-vars: error - ## Enforce consistent spacing before blocks - space-before-blocks: [error, always] - ## Enforce consistent spacing before function definition opening parenthesis - # space-before-function-paren: [error, { - # anonymous: always, - # named: never, - # asyncArrow: always, - # }] - ## Enforce consistent spacing inside parentheses - space-in-parens: [error, never] - ## Require spacing around infix operators - # space-infix-ops: error - ## Enforce consistent spacing before or after unary operators - # space-unary-ops: error - ## Enforce consistent spacing after the // or /* in a comment - spaced-comment: [error, always] - ## Enforce spacing around colons of switch statements - switch-colon-spacing: [error, { before: false, after: true }] - ## Require or disallow spacing between template tags and their literals - template-tag-spacing: [error, never] - ## Require or disallow Unicode byte order mark (BOM) - # unicode-bom: [error, never] - ## Require parenthesis around regex literals - # wrap-regex: error - - ## ES6 - ## ---------------------------------------- - ## Require braces around arrow function bodies - # arrow-body-style: error - ## Require parentheses around arrow function arguments - # arrow-parens: [error, as-needed] - ## Enforce consistent spacing before and after the arrow in arrow functions - arrow-spacing: [error, { before: true, after: true }] - ## Require super() calls in constructors - # constructor-super: error - ## Enforce consistent spacing around * operators in generator functions - generator-star-spacing: [error, { before: false, after: true }] - ## Disallow reassigning class members - no-class-assign: error - ## Disallow arrow functions where they could be confused with comparisons - # no-confusing-arrow: error - ## Disallow reassigning const variables - no-const-assign: error - ## Disallow duplicate class members - no-dupe-class-members: error - ## Disallow duplicate module imports - # no-duplicate-imports: error - ## Disallow new operators with the Symbol object - no-new-symbol: error - ## Disallow specified modules when loaded by import - # no-restricted-imports: error - ## Disallow this/super before calling super() in constructors - no-this-before-super: error - ## Disallow unnecessary computed property keys in object literals - # no-useless-computed-key: error - ## Disallow unnecessary constructors - # no-useless-constructor: error - ## Disallow renaming import, export, and destructured assignments to the - ## same name - # no-useless-rename: error - ## Require let or const instead of var - no-var: error - ## Require or disallow method and property shorthand syntax for object - ## literals - # object-shorthand: error - ## Require using arrow functions for callbacks - prefer-arrow-callback: error - ## Require const declarations for variables that are never reassigned after - ## declared - prefer-const: error - ## Require destructuring from arrays and/or objects - # prefer-destructuring: error - ## Disallow parseInt() and Number.parseInt() in favor of binary, octal, and - ## hexadecimal literals - # prefer-numeric-literals: error - ## Require rest parameters instead of arguments - # prefer-rest-params: error - ## Require spread operators instead of .apply() - # prefer-spread: error - ## Require template literals instead of string concatenation - # prefer-template: error - ## Require generator functions to contain yield - # require-yield: error - ## Enforce spacing between rest and spread operators and their expressions - # rest-spread-spacing: error - ## Enforce sorted import declarations within modules - # sort-imports: error - ## Require symbol descriptions - # symbol-description: error - ## Require or disallow spacing around embedded expressions of template - ## strings - # template-curly-spacing: error - ## Require or disallow spacing around the * in yield* expressions - yield-star-spacing: [error, { before: false, after: true }] - - ## React - ## ---------------------------------------- - ## Enforces consistent naming for boolean props - react/boolean-prop-naming: error - ## Forbid "button" element without an explicit "type" attribute - react/button-has-type: error - ## Prevent extraneous defaultProps on components - react/default-props-match-prop-types: error - ## Rule enforces consistent usage of destructuring assignment in component - # react/destructuring-assignment: [error, always, { ignoreClassFields: true }] - ## Prevent missing displayName in a React component definition - # react/display-name: error - ## Forbid certain props on Components - # react/forbid-component-props: error - ## Forbid certain props on DOM Nodes - # react/forbid-dom-props: error - ## Forbid certain elements - # react/forbid-elements: error - ## Forbid certain propTypes - # react/forbid-prop-types: error - ## Forbid foreign propTypes - # react/forbid-foreign-prop-types: error - ## Prevent using this.state inside this.setState - react/no-access-state-in-setstate: error - ## Prevent using Array index in key props - # react/no-array-index-key: error - ## Prevent passing children as props - react/no-children-prop: error - ## Prevent usage of dangerous JSX properties - react/no-danger: error - ## Prevent problem with children and props.dangerouslySetInnerHTML - react/no-danger-with-children: error - ## Prevent usage of deprecated methods, including component lifecycle - ## methods - react/no-deprecated: error - ## Prevent usage of setState in componentDidMount - react/no-did-mount-set-state: error - ## Prevent usage of setState in componentDidUpdate - react/no-did-update-set-state: error - ## Prevent direct mutation of this.state - react/no-direct-mutation-state: error - ## Prevent usage of findDOMNode - react/no-find-dom-node: error - ## Prevent usage of isMounted - react/no-is-mounted: error - ## Prevent multiple component definition per file - # react/no-multi-comp: error - ## Prevent usage of shouldComponentUpdate when extending React.PureComponent - react/no-redundant-should-component-update: error - ## Prevent usage of the return value of React.render - react/no-render-return-value: error - ## Prevent usage of setState - # react/no-set-state: error - ## Prevent common casing typos - react/no-typos: error - ## Prevent using string references in ref attribute. - react/no-string-refs: error - ## Prevent using this in stateless functional components - react/no-this-in-sfc: error - ## Prevent invalid characters from appearing in markup - react/no-unescaped-entities: error - ## Prevent usage of unknown DOM property (fixable) - # react/no-unknown-property: error - ## Prevent usage of unsafe lifecycle methods - react/no-unsafe: error - ## Prevent definitions of unused prop types - react/no-unused-prop-types: error - ## Prevent definitions of unused state properties - react/no-unused-state: error - ## Prevent usage of setState in componentWillUpdate - react/no-will-update-set-state: error - ## Enforce ES5 or ES6 class for React Components - react/prefer-es6-class: error - ## Enforce that props are read-only - react/prefer-read-only-props: off - ## Enforce stateless React Components to be written as a pure function - react/prefer-stateless-function: error - ## Prevent missing props validation in a React component definition - # react/prop-types: error - ## Prevent missing React when using JSX - # react/react-in-jsx-scope: error - ## Enforce a defaultProps definition for every prop that is not a required - ## prop - # react/require-default-props: error - ## Enforce React components to have a shouldComponentUpdate method - # react/require-optimization: error - ## Enforce ES5 or ES6 class for returning value in render function - react/require-render-return: error - ## Prevent extra closing tags for components without children (fixable) - react/self-closing-comp: error - ## Enforce component methods order (fixable) - # react/sort-comp: error - ## Enforce propTypes declarations alphabetical sorting - # react/sort-prop-types: error - ## Enforce the state initialization style to be either in a constructor or - ## with a class property - # react/state-in-constructor: error - ## Enforces where React component static properties should be positioned. - # react/static-property-placement: error - ## Enforce style prop value being an object - react/style-prop-object: error - ## Prevent void DOM elements (e.g. ,
) from receiving children - react/void-dom-elements-no-children: error - - ## JSX-specific rules - ## ---------------------------------------- - ## Enforce boolean attributes notation in JSX (fixable) - react/jsx-boolean-value: error - ## Enforce or disallow spaces inside of curly braces in JSX attributes and - ## expressions. - # react/jsx-child-element-spacing: error - ## Validate closing bracket location in JSX (fixable) - # react/jsx-closing-bracket-location: [error, { - # ## NOTE: Not really sure about enforcing this one - # selfClosing: false, - # nonEmpty: after-props, - # }] - ## Validate closing tag location in JSX (fixable) - react/jsx-closing-tag-location: error - ## Enforce or disallow newlines inside of curly braces in JSX attributes and - ## expressions (fixable) - # react/jsx-curly-newline: error - ## Enforce or disallow spaces inside of curly braces in JSX attributes and - ## expressions (fixable) - react/jsx-curly-spacing: error - ## Enforce or disallow spaces around equal signs in JSX attributes (fixable) - react/jsx-equals-spacing: error - ## Restrict file extensions that may contain JSX - # react/jsx-filename-extension: error - ## Enforce position of the first prop in JSX (fixable) - # react/jsx-first-prop-new-line: error - ## Enforce event handler naming conventions in JSX - react/jsx-handler-names: error - ## Validate JSX indentation (fixable) - # react/jsx-indent: [error, 2, { - # checkAttributes: true, - # }] - ## Validate props indentation in JSX (fixable) - # react/jsx-indent-props: [error, 2] - ## Validate JSX has key prop when in array or iterator - react/jsx-key: error - ## Validate JSX maximum depth - react/jsx-max-depth: [error, { max: 10 }] ## Generous - ## Limit maximum of props on a single line in JSX (fixable) - # react/jsx-max-props-per-line: error - ## Prevent usage of .bind() and arrow functions in JSX props - # react/jsx-no-bind: error - ## Prevent comments from being inserted as text nodes - react/jsx-no-comment-textnodes: error - ## Prevent duplicate props in JSX - react/jsx-no-duplicate-props: error - ## Prevent usage of unwrapped JSX strings - # react/jsx-no-literals: error - ## Prevent usage of unsafe target='_blank' - react/jsx-no-target-blank: error - ## Disallow undeclared variables in JSX - react/jsx-no-undef: error - ## Disallow unnecessary fragments (fixable) - react/jsx-no-useless-fragment: error - ## Limit to one expression per line in JSX - # react/jsx-one-expression-per-line: error - ## Enforce curly braces or disallow unnecessary curly braces in JSX - # react/jsx-curly-brace-presence: error - ## Enforce shorthand or standard form for React fragments - react/jsx-fragments: error - ## Enforce PascalCase for user-defined JSX components - react/jsx-pascal-case: error - ## Disallow multiple spaces between inline JSX props (fixable) - react/jsx-props-no-multi-spaces: error - ## Disallow JSX props spreading - # react/jsx-props-no-spreading: error - ## Enforce default props alphabetical sorting - # react/jsx-sort-default-props: error - ## Enforce props alphabetical sorting (fixable) - # react/jsx-sort-props: error - ## Validate whitespace in and around the JSX opening and closing brackets - ## (fixable) - react/jsx-tag-spacing: error - ## Prevent React to be incorrectly marked as unused - react/jsx-uses-react: error - ## Prevent variables used in JSX to be incorrectly marked as unused - react/jsx-uses-vars: error - ## Prevent missing parentheses around multilines JSX (fixable) - react/jsx-wrap-multilines: error - ## Prevents the use of unused imports. - ## This could be done by enabling no-unused-vars, but we're doing this for now - unused-imports/no-unused-imports: error - ## https://github.com/lydell/eslint-plugin-simple-import-sort/ - simple-import-sort/imports: error - simple-import-sort/exports: error - - ## Typescript - '@typescript-eslint/consistent-type-imports': - [error, { fixStyle: inline-type-imports }] diff --git a/tgui/.prettierignore b/tgui/.prettierignore index eac862f94a0..64ad6361de2 100644 --- a/tgui/.prettierignore +++ b/tgui/.prettierignore @@ -1,5 +1,12 @@ node_modules public +*.js +*.ts +*.tsx +*.css +*.jsx +*.json + # Running it on tgui.html is fine, however. !/public/tgui.html diff --git a/tgui/bun.lock b/tgui/bun.lock index 8eaf2176ad0..53cb3942c1f 100644 --- a/tgui/bun.lock +++ b/tgui/bun.lock @@ -3,30 +3,19 @@ "workspaces": { "": { "name": "tgui-workspace", - "dependencies": { - "@rspack/cli": "^1.4.8", - "@rspack/core": "^1.4.8", - "@typescript-eslint/eslint-plugin": "^8.37.0", - "@typescript-eslint/parser": "^8.37.0", - "@typescript-eslint/utils": "^8.37.0", - "css-loader": "^7.1.2", - "eslint": "^8.57.1", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-simple-import-sort": "^12.1.1", - "eslint-plugin-unused-imports": "^4.1.4", - "prettier": "^3.6.2", - "sass-embedded": "^1.89.2", - "sass-loader": "^16.0.5", - "typescript": "^5.8.3", - }, "devDependencies": { "@happy-dom/global-registrator": "^17.6.3", + "@rspack/cli": "^1.4.8", + "@rspack/core": "^1.4.8", "@types/bun": "^1.2.18", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", "@types/webpack-env": "^1.18.8", "@types/wicg-file-system-access": "^2023.10.6", + "css-loader": "^7.1.2", + "sass-embedded": "^1.89.2", + "sass-loader": "^16.0.5", + "typescript": "^5.8.3", }, }, "packages/common": { @@ -117,14 +106,6 @@ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="], - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="], - - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], - - "@eslint/eslintrc": ["@eslint/eslintrc@2.1.4", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ=="], - - "@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="], - "@floating-ui/core": ["@floating-ui/core@1.7.2", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw=="], "@floating-ui/dom": ["@floating-ui/dom@1.7.2", "", { "dependencies": { "@floating-ui/core": "^1.7.2", "@floating-ui/utils": "^0.2.10" } }, "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA=="], @@ -137,12 +118,6 @@ "@happy-dom/global-registrator": ["@happy-dom/global-registrator@17.6.3", "", { "dependencies": { "happy-dom": "^17.6.3" } }, "sha512-SE8Mu6bdkgKENemVg20yMrKdYeAvVesQrLPVfNBKnhicCM3ylHV9oIDzDMxSFj3qYCrHrIWOZsItOXSafrM4Tw=="], - "@humanwhocodes/config-array": ["@humanwhocodes/config-array@0.13.0", "", { "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", "minimatch": "^3.0.5" } }, "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw=="], - - "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], - - "@humanwhocodes/object-schema": ["@humanwhocodes/object-schema@2.0.3", "", {}, "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA=="], - "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], @@ -183,12 +158,6 @@ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@0.2.12", "", { "dependencies": { "@emnapi/core": "^1.4.3", "@emnapi/runtime": "^1.4.3", "@tybys/wasm-util": "^0.10.0" } }, "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ=="], - "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], - - "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], - - "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], - "@nozbe/microfuzz": ["@nozbe/microfuzz@1.0.0", "", {}, "sha512-XKIg/guk+s1tkPTkHch9hfGOWgsKojT7BqSQddXTppOfVr3SWQhhTCqbgQaPTbppf9gc2kFeG0gpBZZ612UXHA=="], "@npmcli/agent": ["@npmcli/agent@2.2.2", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^10.0.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og=="], @@ -321,28 +290,6 @@ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.37.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/type-utils": "8.37.0", "@typescript-eslint/utils": "8.37.0", "@typescript-eslint/visitor-keys": "8.37.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.37.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-jsuVWeIkb6ggzB+wPCsR4e6loj+rM72ohW6IBn2C+5NCvfUVY8s33iFPySSVXqtm5Hu29Ne/9bnA0JmyLmgenA=="], - - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.37.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/types": "8.37.0", "@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/visitor-keys": "8.37.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-kVIaQE9vrN9RLCQMQ3iyRlVJpTiDUY6woHGb30JDkfJErqrQEmtdWH3gV0PBAfGZgQXoqzXOO0T3K6ioApbbAA=="], - - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.37.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.37.0", "@typescript-eslint/types": "^8.37.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-BIUXYsbkl5A1aJDdYJCBAo8rCEbAvdquQ8AnLb6z5Lp1u3x5PNgSSx9A/zqYc++Xnr/0DVpls8iQ2cJs/izTXA=="], - - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.37.0", "", { "dependencies": { "@typescript-eslint/types": "8.37.0", "@typescript-eslint/visitor-keys": "8.37.0" } }, "sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA=="], - - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.37.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg=="], - - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.37.0", "", { "dependencies": { "@typescript-eslint/types": "8.37.0", "@typescript-eslint/typescript-estree": "8.37.0", "@typescript-eslint/utils": "8.37.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow=="], - - "@typescript-eslint/types": ["@typescript-eslint/types@8.37.0", "", {}, "sha512-ax0nv7PUF9NOVPs+lmQ7yIE7IQmAf8LGcXbMvHX5Gm+YJUYNAl340XkGnrimxZ0elXyoQJuN5sbg6C4evKA4SQ=="], - - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.37.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.37.0", "@typescript-eslint/tsconfig-utils": "8.37.0", "@typescript-eslint/types": "8.37.0", "@typescript-eslint/visitor-keys": "8.37.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg=="], - - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.37.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.37.0", "@typescript-eslint/types": "8.37.0", "@typescript-eslint/typescript-estree": "8.37.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A=="], - - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.37.0", "", { "dependencies": { "@typescript-eslint/types": "8.37.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-YzfhzcTnZVPiLfP/oeKtDp2evwvHLMe0LOy7oe+hb9KKIumLNohYS9Hgp1ifwpu42YWxhZE8yieggz6JpqO/1w=="], - - "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], - "@webassemblyjs/ast": ["@webassemblyjs/ast@1.14.1", "", { "dependencies": { "@webassemblyjs/helper-numbers": "1.13.2", "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ=="], "@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.13.2", "", {}, "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA=="], @@ -395,7 +342,7 @@ "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], - "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], "ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="], @@ -413,32 +360,14 @@ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], - "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], - "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], - "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], - - "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], - - "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], - - "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-shim-unscopables": "^1.0.2" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], - - "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.3", "es-errors": "^1.3.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], - - "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], - "asap": ["asap@2.0.6", "", {}, "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="], - "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], - "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], "auto-config-loader": ["auto-config-loader@2.0.2", "", { "dependencies": { "ini": "^5.0.0", "jiti": "^2.4.1", "jsonc-eslint-parser": "^2.3.0", "lodash.merge": "^4.6.2", "sucrase": "^3.35.0", "toml-eslint-parser": "^0.10.0", "yaml-eslint-parser": "^1.2.2" } }, "sha512-0V8gZAGGqiFDP15d6d4/Emi6Gpozbr1S9lSfxJ+lNV8nF+7grhcgbHIgn3O/DQKybS+cDqVMC3rxH8k+o0ISpA=="], - "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], - "axios": ["axios@1.10.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], @@ -475,18 +404,12 @@ "cacache": ["cacache@18.0.4", "", { "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", "ssri": "^10.0.0", "tar": "^6.1.11", "unique-filename": "^3.0.0" } }, "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ=="], - "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], - "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], - "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], - "caniuse-lite": ["caniuse-lite@1.0.30001723", "", {}, "sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw=="], - "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "cheerio": ["cheerio@1.0.0", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.1.0", "encoding-sniffer": "^0.2.0", "htmlparser2": "^9.1.0", "parse5": "^7.1.2", "parse5-htmlparser2-tree-adapter": "^7.0.0", "parse5-parser-stream": "^7.1.2", "undici": "^6.19.5", "whatwg-mimetype": "^4.0.0" } }, "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww=="], "cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="], @@ -559,30 +482,18 @@ "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], - "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], - - "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-data-view": "^1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], - - "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], - "dateformat": ["dateformat@5.0.3", "", {}, "sha512-Kvr6HmPXUMerlLcLF+Pwq3K7apHpYmGDVqrxcDasBg86UcKeTSNWbEzU8bwdXnxnR44FtMhJAxI4Bov6Y/KUfA=="], "debounce": ["debounce@1.2.1", "", {}, "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="], "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], - "default-browser": ["default-browser@5.2.1", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg=="], "default-browser-id": ["default-browser-id@5.0.0", "", {}, "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA=="], - "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], - "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], - "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], - "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], @@ -595,8 +506,6 @@ "dns-packet": ["dns-packet@5.6.1", "", { "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" } }, "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw=="], - "doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="], - "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], @@ -633,24 +542,16 @@ "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="], - "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], - "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - "es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="], - "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], - "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], - - "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], - "es-toolkit": ["es-toolkit@1.39.7", "", {}, "sha512-ek/wWryKouBrZIjkwW2BFf91CWOIMvoy2AE5YYgUrfWsJQM2Su1LoLtrw8uusEpN9RfqLlV/0FVNjT0WMv8Bxw=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -659,29 +560,15 @@ "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], - "eslint": ["eslint@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", "@eslint/js": "8.57.1", "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA=="], - - "eslint-config-prettier": ["eslint-config-prettier@9.1.0", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw=="], - - "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], - - "eslint-plugin-simple-import-sort": ["eslint-plugin-simple-import-sort@12.1.1", "", { "peerDependencies": { "eslint": ">=5.0.0" } }, "sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA=="], - - "eslint-plugin-unused-imports": ["eslint-plugin-unused-imports@4.1.4", "", { "peerDependencies": { "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", "eslint": "^9.0.0 || ^8.0.0" }, "optionalPeers": ["@typescript-eslint/eslint-plugin"] }, "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ=="], - - "eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="], + "eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], "eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="], - "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], - "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], - "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], - - "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + "estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], @@ -697,38 +584,20 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], - "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], - - "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], - - "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - "fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="], - "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], - "faye-websocket": ["faye-websocket@0.11.4", "", { "dependencies": { "websocket-driver": ">=0.5.1" } }, "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g=="], "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], - "file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "^3.0.4" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="], - "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], "finalhandler": ["finalhandler@1.3.1", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ=="], - "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], - - "flat-cache": ["flat-cache@3.2.0", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" } }, "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw=="], - - "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], - "follow-redirects": ["follow-redirects@1.15.9", "", {}, "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ=="], - "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], - "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], "form-data": ["form-data@4.0.3", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA=="], @@ -749,48 +618,30 @@ "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], - "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "functions-have-names": "^1.2.3", "hasown": "^2.0.2", "is-callable": "^1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], - - "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], - "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], - "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], - "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], - "globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="], - - "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], - "gzip-size": ["gzip-size@6.0.0", "", { "dependencies": { "duplexer": "^0.1.2" } }, "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="], "handle-thing": ["handle-thing@2.0.1", "", {}, "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg=="], "happy-dom": ["happy-dom@17.6.3", "", { "dependencies": { "webidl-conversions": "^7.0.0", "whatwg-mimetype": "^3.0.0" } }, "sha512-UVIHeVhxmxedbWPCfgS55Jg2rDfwf2BCKeylcPSqazLz5w3Kri7Q4xdBJubsr/+VUzFLh0VjIvh13RaDA2/Xug=="], - "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], - "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], - "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], - - "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "^1.0.0" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], - "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], @@ -827,14 +678,10 @@ "icss-utils": ["icss-utils@5.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA=="], - "ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], - "image2uri": ["image2uri@2.1.2", "", { "dependencies": { "node-fetch": "^3.3.1" } }, "sha512-3b2zRma8I3zulb4OCkZruRw1VsnysT9phBzOJj+x3lPkwybJtNa5Sz6Dw8jSQI6OL7Ns4H5h8Y26EJbwq4GhQQ=="], "immutable": ["immutable@5.1.3", "", {}, "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg=="], - "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], @@ -845,87 +692,39 @@ "ini": ["ini@5.0.0", "", {}, "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw=="], - "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], - "interpret": ["interpret@3.1.1", "", {}, "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ=="], "ip-address": ["ip-address@9.0.5", "", { "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" } }, "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g=="], "ipaddr.js": ["ipaddr.js@2.2.0", "", {}, "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA=="], - "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], - - "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "^1.0.0", "call-bound": "^1.0.3", "get-proto": "^1.0.1", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], - - "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "^1.0.2" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], - "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], - - "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], - "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], - "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], - - "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "has-tostringtag": "^1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], - "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], - "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], - "is-generator-function": ["is-generator-function@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "get-proto": "^1.0.0", "has-tostringtag": "^1.0.2", "safe-regex-test": "^1.1.0" } }, "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ=="], - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], "is-lambda": ["is-lambda@1.0.1", "", {}, "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ=="], - "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], - - "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], - "is-network-error": ["is-network-error@1.1.0", "", {}, "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g=="], "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], - - "is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="], - "is-plain-obj": ["is-plain-obj@3.0.0", "", {}, "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA=="], - "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], - - "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], - - "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], - - "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], - - "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", "safe-regex-test": "^1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], - - "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], - - "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], - - "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "^1.0.3" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], - - "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], - "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], - "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], - - "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], + "isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], "jackspeak": ["jackspeak@4.1.1", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ=="], @@ -933,44 +732,28 @@ "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="], - "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], "jsbn": ["jsbn@1.1.0", "", {}, "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="], - "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], - "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], - "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - - "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "jsonc-eslint-parser": ["jsonc-eslint-parser@2.4.0", "", { "dependencies": { "acorn": "^8.5.0", "eslint-visitor-keys": "^3.0.0", "espree": "^9.0.0", "semver": "^7.3.5" } }, "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg=="], "jsonfile": ["jsonfile@6.1.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="], - "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", "object.assign": "^4.1.4", "object.values": "^1.1.6" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], - - "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], - "launch-editor": ["launch-editor@2.10.0", "", { "dependencies": { "picocolors": "^1.0.0", "shell-quote": "^1.8.1" } }, "sha512-D7dBRJo/qcGX9xlvt/6wUYzQxjh5G1RvZPgPv8vi4KRU99DVQL/oW7tnVOCCTm2HGeo3C5HvGE5Yrh6UBoZ0vA=="], - "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], "loader-runner": ["loader-runner@4.3.0", "", {}, "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="], - "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], - "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - "lru-cache": ["lru-cache@11.1.0", "", {}, "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A=="], "make-fetch-happen": ["make-fetch-happen@13.0.1", "", { "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", "http-cache-semantics": "^4.1.1", "is-lambda": "^1.0.1", "minipass": "^7.0.2", "minipass-fetch": "^3.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" } }, "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA=="], @@ -993,8 +776,6 @@ "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], - "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], "microbuffer": ["microbuffer@1.0.0", "", {}, "sha512-O/SUXauVN4x6RaEJFqSPcXNtLFL+QzJHKZlyDVYFwcDDRVca3Fa/37QXXC+4zAGGa4YhHrHxKXuuHvLDIQECtA=="], @@ -1039,8 +820,6 @@ "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], - "negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], @@ -1069,16 +848,6 @@ "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], - "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], - - "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], - - "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-object-atoms": "^1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], - - "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-object-atoms": "^1.0.0" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], - - "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "obuf": ["obuf@1.1.2", "", {}, "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="], "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], @@ -1091,14 +860,6 @@ "opener": ["opener@1.5.2", "", { "bin": { "opener": "bin/opener-bin.js" } }, "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="], - "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], - - "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], - - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - - "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], - "p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="], "p-retry": ["p-retry@6.2.1", "", { "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", "retry": "^0.13.1" } }, "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ=="], @@ -1107,8 +868,6 @@ "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], - "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], - "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@7.1.0", "", { "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" } }, "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g=="], @@ -1117,8 +876,6 @@ "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], - "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], - "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], @@ -1135,8 +892,6 @@ "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], - "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], "postcss-modules-extract-imports": ["postcss-modules-extract-imports@3.1.0", "", { "peerDependencies": { "postcss": "^8.1.0" } }, "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q=="], @@ -1151,28 +906,18 @@ "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], - "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - - "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], - "proc-log": ["proc-log@4.2.0", "", {}, "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA=="], "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], - "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], - "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], - "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], @@ -1183,48 +928,28 @@ "react-dom": ["react-dom@19.1.0", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.0" } }, "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g=="], - "react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], - "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "rechoir": ["rechoir@0.8.0", "", { "dependencies": { "resolve": "^1.20.0" } }, "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ=="], - "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], - - "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", "get-proto": "^1.0.1", "gopd": "^1.2.0", "set-function-name": "^2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], - "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], - "resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], - - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], - "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - - "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "run-applescript": ["run-applescript@7.0.0", "", {}, "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A=="], - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], - "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], - "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], - "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "isarray": "^2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], - - "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], - "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], "sass": ["sass@1.89.2", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA=="], @@ -1285,12 +1010,6 @@ "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], - "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], - - "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], - - "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], - "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -1339,30 +1058,16 @@ "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], - "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], - "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "regexp.prototype.flags": "^1.5.3", "set-function-name": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], - - "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], - - "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-data-property": "^1.1.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-object-atoms": "^1.0.0", "has-property-descriptors": "^1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], - - "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], - - "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], - "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - "sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="], "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], @@ -1395,8 +1100,6 @@ "terser-webpack-plugin": ["terser-webpack-plugin@5.3.14", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "peerDependencies": { "webpack": "^5.1.0" } }, "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw=="], - "text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], - "tgfont": ["tgfont@workspace:packages/tgfont"], "tgui": ["tgui@workspace:packages/tgui"], @@ -1431,8 +1134,6 @@ "tree-dump": ["tree-dump@1.0.3", "", { "peerDependencies": { "tslib": "2" } }, "sha512-il+Cv80yVHFBwokQSfd4bldvr1Md951DpgAGfmhydt04L+YzHgubm2tQ7zueWDcGENKHq0ZvGFR/hjvNXilHEg=="], - "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], - "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -1443,24 +1144,12 @@ "ttf2woff2": ["ttf2woff2@6.0.1", "", { "dependencies": { "bindings": "^1.5.0", "bufferstreams": "^4.0.0", "debug": "^4.3.5", "nan": "^2.20.0", "node-gyp": "^10.2.0", "yerror": "^8.0.0" }, "bin": { "ttf2woff2": "bin/ttf2woff2.js" } }, "sha512-QVkHvd4VsJ9cZNnzrfJL4Fhl5tyGkO5ih9PRY3DQ2BicKjyA+92I+00H2p06mBw1d0eCtzSQh5bp7NTUA57trg=="], - "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], - "type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], - "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], - - "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.14" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], - - "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "for-each": "^0.3.3", "gopd": "^1.2.0", "has-proto": "^1.2.0", "is-typed-array": "^1.1.15", "reflect.getprototypeof": "^1.0.9" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], - - "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", "is-typed-array": "^1.1.13", "possible-typed-array-names": "^1.0.0", "reflect.getprototypeof": "^1.0.6" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], - "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], - "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], - "undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="], "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], @@ -1475,8 +1164,6 @@ "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], - "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], - "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], @@ -1513,17 +1200,7 @@ "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], - "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], - - "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", "is-number-object": "^1.1.1", "is-string": "^1.1.1", "is-symbol": "^1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], - - "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "^1.0.2", "function.prototype.name": "^1.1.6", "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.1.0", "is-finalizationregistry": "^1.1.0", "is-generator-function": "^1.0.10", "is-regex": "^1.2.1", "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.1.0", "which-collection": "^1.0.2", "which-typed-array": "^1.1.16" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], - - "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], - - "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], - - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + "which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], @@ -1547,10 +1224,6 @@ "yerror": ["yerror@8.0.0", "", {}, "sha512-FemWD5/UqNm8ffj8oZIbjWXIF2KE0mZssggYpdaQkWDDgXBQ/35PNIxEuz6/YLn9o0kOxDBNJe8x8k9ljD7k/g=="], - "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - - "@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], @@ -1559,16 +1232,8 @@ "@npmcli/agent/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], - "accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "ajv-formats/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], - - "ajv-keywords/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], - "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "body-parser/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], @@ -1579,34 +1244,24 @@ "cacache/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "cheerio/whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], - "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "clean-css/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], - "eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - - "eslint-plugin-react/doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], - - "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], - "globals/type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="], - "hpack.js/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], @@ -1619,8 +1274,6 @@ "node-gyp/glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], - "node-gyp/which": ["which@4.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg=="], - "nunjucks/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="], "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], @@ -1631,12 +1284,8 @@ "raw-body/iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], - "rechoir/resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], - "sass/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - "schema-utils/ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "send/encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], @@ -1659,8 +1308,6 @@ "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], - "webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="], - "webpack-bundle-analyzer/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], @@ -1669,12 +1316,6 @@ "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], - "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - - "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - - "ajv-keywords/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "cacache/glob/jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], @@ -1685,14 +1326,14 @@ "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], "express/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "hpack.js/readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], - "hpack.js/readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], "hpack.js/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], @@ -1703,12 +1344,8 @@ "node-gyp/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "node-gyp/which/isexe": ["isexe@3.1.1", "", {}, "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ=="], - "sass/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], - "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "serve-index/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -1729,8 +1366,6 @@ "svgicons2svgfont/glob/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], - "webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], - "cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "node-gyp/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], diff --git a/tgui/package.json b/tgui/package.json index bc4c76dc56c..d751be25bd8 100644 --- a/tgui/package.json +++ b/tgui/package.json @@ -10,36 +10,21 @@ "tgui:analyze": "rspack --analyze", "tgui:build": "rspack build", "tgui:dev": "bun --smol packages/tgui-dev-server/index.ts", - "tgui:lint": "eslint packages --ext .js,.cjs,.ts,.tsx", - "tgui:prettier": "prettier --check .", "tgui:test": "bun test", - "tgui:tsc": "tsc", - "tgui:prettier-fix": "prettier --write .", - "tgui:eslint-fix": "eslint --fix packages --ext .js,.cjs,.ts,.jsx,.tsx" - }, - "dependencies": { - "@rspack/cli": "^1.4.8", - "@rspack/core": "^1.4.8", - "@typescript-eslint/eslint-plugin": "^8.37.0", - "@typescript-eslint/parser": "^8.37.0", - "@typescript-eslint/utils": "^8.37.0", - "css-loader": "^7.1.2", - "eslint": "^8.57.1", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-simple-import-sort": "^12.1.1", - "eslint-plugin-unused-imports": "^4.1.4", - "prettier": "^3.6.2", - "sass-embedded": "^1.89.2", - "sass-loader": "^16.0.5", - "typescript": "^5.8.3" + "tgui:tsc": "tsc" }, "devDependencies": { "@happy-dom/global-registrator": "^17.6.3", + "@rspack/cli": "^1.4.8", + "@rspack/core": "^1.4.8", "@types/bun": "^1.2.18", "@types/react": "^19.1.8", "@types/react-dom": "^19.1.6", "@types/webpack-env": "^1.18.8", - "@types/wicg-file-system-access": "^2023.10.6" + "@types/wicg-file-system-access": "^2023.10.6", + "css-loader": "^7.1.2", + "sass-embedded": "^1.89.2", + "sass-loader": "^16.0.5", + "typescript": "^5.8.3" } } diff --git a/tgui/packages/common/colorpicker.ts b/tgui/packages/common/colorpicker.ts index 494ab3ea7fd..95449c4c83c 100644 --- a/tgui/packages/common/colorpicker.ts +++ b/tgui/packages/common/colorpicker.ts @@ -11,11 +11,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -const round = ( - number: number, - digits = 0, - base = Math.pow(10, digits), -): number => { +const round = (number: number, digits = 0, base = 10 ** digits): number => { return Math.round(base * number) / base; }; export interface RgbColor { @@ -185,25 +181,23 @@ export const rgbaStringToHsva = (rgbaString: string): HsvaColor => { export const rgbStringToHsva = rgbaStringToHsva; const format = (number: number) => { const hex = number.toString(16); - return hex.length < 2 ? '0' + hex : hex; + return hex.length < 2 ? `0${hex}` : hex; }; export const rgbaToHex = ({ r, g, b, a }: RgbaColor): string => { const alphaHex = a < 1 ? format(round(a * 255)) : ''; - return ( - '#' + format(round(r)) + format(round(g)) + format(round(b)) + alphaHex - ); + return `#${format(round(r))}${format(round(g))}${format(round(b))}${alphaHex}`; }; export const rgbaToHsva = ({ r, g, b, a }: RgbaColor): HsvaColor => { const max = Math.max(r, g, b); const delta = max - Math.min(r, g, b); // prettier-ignore const hh = delta - ? max === r - ? (g - b) / delta - : max === g - ? 2 + (b - r) / delta - : 4 + (r - g) / delta - : 0; + ? max === r + ? (g - b) / delta + : max === g + ? 2 + (b - r) / delta + : 4 + (r - g) / delta + : 0; return { h: 60 * (hh < 0 ? hh + 6 : hh), s: max ? (delta / max) * 100 : 0, @@ -238,7 +232,7 @@ export const validHex = (value: string, alpha?: boolean): boolean => { export const luminance = (rgb: RgbColor): number => { const [r, g, b] = [rgb.r, rgb.g, rgb.b].map((v) => { v /= 255; - return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); + return v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4; }); return r * 0.2126 + g * 0.7152 + b * 0.0722; }; diff --git a/tgui/packages/common/storage.ts b/tgui/packages/common/storage.ts index 1fe8ec0383f..ba3e28c08b6 100644 --- a/tgui/packages/common/storage.ts +++ b/tgui/packages/common/storage.ts @@ -46,7 +46,7 @@ class HubStorageBackend implements StorageBackend { } async get(key: string): Promise { - const value = await window.hubStorage.getItem('virgo-' + key); + const value = await window.hubStorage.getItem(`virgo-${key}`); if (typeof value === 'string') { return JSON.parse(value); } @@ -54,11 +54,11 @@ class HubStorageBackend implements StorageBackend { } async set(key: string, value: any): Promise { - window.hubStorage.setItem('virgo-' + key, JSON.stringify(value)); + window.hubStorage.setItem(`virgo-${key}`, JSON.stringify(value)); } async remove(key: string): Promise { - window.hubStorage.removeItem('virgo-' + key); + window.hubStorage.removeItem(`virgo-${key}`); } async clear(): Promise { diff --git a/tgui/packages/tgui-dev-server/dreamseeker.ts b/tgui/packages/tgui-dev-server/dreamseeker.ts index 8e186ef3d82..90e26b914c4 100644 --- a/tgui/packages/tgui-dev-server/dreamseeker.ts +++ b/tgui/packages/tgui-dev-server/dreamseeker.ts @@ -37,13 +37,13 @@ export class DreamSeeker { const query = Object.keys(params) .map( (key) => - encodeURIComponent(key) + '=' + encodeURIComponent(params[key]), + `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`, ) .join('&'); logger.log( `topic call at ${this.client.defaults.baseURL}/dummy.htm?${query}`, ); - return this.client.get('/dummy.htm?' + query); + return this.client.get(`/dummy.htm?${query}`); } static async getInstancesByPids(pids: number[]): Promise { @@ -111,5 +111,5 @@ export class DreamSeeker { } function plural(word: string, n: number): string { - return n !== 1 ? word + 's' : word; + return n !== 1 ? `${word}s` : word; } diff --git a/tgui/packages/tgui-dev-server/link/retrace.ts b/tgui/packages/tgui-dev-server/link/retrace.ts index 0560c40aa56..6fd1bc27ab0 100644 --- a/tgui/packages/tgui-dev-server/link/retrace.ts +++ b/tgui/packages/tgui-dev-server/link/retrace.ts @@ -84,5 +84,5 @@ export function retrace(stack: string): string | undefined { }) .join('\n'); - return header + '\n' + mappedStack; + return `${header}\n${mappedStack}`; } diff --git a/tgui/packages/tgui-dev-server/link/server.ts b/tgui/packages/tgui-dev-server/link/server.ts index a2d854af0a7..e618bb15ecc 100644 --- a/tgui/packages/tgui-dev-server/link/server.ts +++ b/tgui/packages/tgui-dev-server/link/server.ts @@ -1,6 +1,6 @@ import { inspect } from 'node:util'; -import { type ServerWebSocket } from 'bun'; +import type { ServerWebSocket } from 'bun'; import { createLogger, directLog } from '../logging'; import { retrace } from './retrace'; diff --git a/tgui/packages/tgui-dev-server/reloader.ts b/tgui/packages/tgui-dev-server/reloader.ts index 19c7e27a27c..fdbb2aa066c 100644 --- a/tgui/packages/tgui-dev-server/reloader.ts +++ b/tgui/packages/tgui-dev-server/reloader.ts @@ -61,7 +61,7 @@ export async function findCacheRoot(): Promise { 'userpath', ); if (userpath) { - cacheRoot = userpath.replace(/\\$/, '').replace(/\\/g, '/') + '/cache'; + cacheRoot = `${userpath.replace(/\\$/, '').replace(/\\/g, '/')}/cache`; await onCacheRootFound(cacheRoot); return cacheRoot; } @@ -72,7 +72,7 @@ export async function findCacheRoot(): Promise { async function onCacheRootFound(cacheRoot: string): Promise { logger.log(`found cache at '${cacheRoot}'`); // Plant a dummy browser window file, we'll be using this to avoid world topic. For byond 514. - await Bun.write(cacheRoot + '/dummy.htm', ''); + await Bun.write(`${cacheRoot}/dummy.htm`, ''); } export async function reloadByondCache(bundleDir: string): Promise { @@ -103,7 +103,7 @@ export async function reloadByondCache(bundleDir: string): Promise { try { // Plant a dummy browser window file, we'll be using this to avoid world topic. For byond 515-516. - await Bun.write(cacheDir + '/dummy.htm', ''); + await Bun.write(`${cacheDir}/dummy.htm`, ''); // Copy assets for (const asset of assets) { diff --git a/tgui/packages/tgui-panel/audio/NowPlayingWidget.tsx b/tgui/packages/tgui-panel/audio/NowPlayingWidget.tsx index 889dd19f55d..22031ddb61d 100644 --- a/tgui/packages/tgui-panel/audio/NowPlayingWidget.tsx +++ b/tgui/packages/tgui-panel/audio/NowPlayingWidget.tsx @@ -28,7 +28,7 @@ export const NowPlayingWidget = (props) => { upload_date = audio.meta?.upload_date || 'Unknown Date', album = audio.meta?.album || 'Unknown Album', duration = audio.meta?.duration, - date = !isNaN(Number(upload_date)) + date = !Number.isNaN(Number(upload_date)) ? upload_date?.substring(0, 4) + '-' + upload_date?.substring(4, 6) + @@ -105,7 +105,7 @@ export const NowPlayingWidget = (props) => { value={settings.adminMusicVolume} step={0.0025} stepPixelSize={1} - format={(value) => toFixed(value * 100) + '%'} + format={(value) => `${toFixed(value * 100)}%`} onDrag={(e, value) => settings.update({ adminMusicVolume: value, diff --git a/tgui/packages/tgui-panel/audio/player.ts b/tgui/packages/tgui-panel/audio/player.ts index e9900693126..21b791c3009 100644 --- a/tgui/packages/tgui-panel/audio/player.ts +++ b/tgui/packages/tgui-panel/audio/player.ts @@ -28,8 +28,8 @@ export class AudioPlayer { options: AudioOptions; volume: number; - onPlaySubscribers: { (): void }[]; - onStopSubscribers: { (): void }[]; + onPlaySubscribers: (() => void)[]; + onStopSubscribers: (() => void)[]; constructor() { this.element = null; diff --git a/tgui/packages/tgui-panel/chat/chatExport.ts b/tgui/packages/tgui-panel/chat/chatExport.ts index e9ada4ceb57..6c7a8fb38e4 100644 --- a/tgui/packages/tgui-panel/chat/chatExport.ts +++ b/tgui/packages/tgui-panel/chat/chatExport.ts @@ -113,7 +113,7 @@ async function getRound( for (const message of messages) { // Filter messages according to active tab for export if (page && canPageAcceptType(page, message.type)) { - messagesHtml += message.html + '\n'; + messagesHtml += `${message.html}\n`; } } diff --git a/tgui/packages/tgui-panel/chat/middleware.ts b/tgui/packages/tgui-panel/chat/middleware.ts index 524ae248419..5d7f627ee87 100644 --- a/tgui/packages/tgui-panel/chat/middleware.ts +++ b/tgui/packages/tgui-panel/chat/middleware.ts @@ -284,23 +284,22 @@ export const chatMiddleware = (store) => { } const sequence_count = sequences.length; - seq_check: if (sequence_count > 0) { + if (sequence_count > 0) { if (sequences_requested.includes(sequence)) { sequences_requested.splice(sequences_requested.indexOf(sequence), 1); // if we are receiving a message we requested, we can stop reliability checks - break seq_check; - } - - // cannot do reliability if we don't have any messages - const expected_sequence = sequences[sequence_count - 1] + 1; - if (sequence !== expected_sequence) { - for ( - let requesting = expected_sequence; - requesting < sequence; - requesting++ - ) { - sequences_requested.push(requesting); - Byond.sendMessage('chat/resend', requesting); + } else { + // cannot do reliability if we don't have any messages + const expected_sequence = sequences[sequence_count - 1] + 1; + if (sequence !== expected_sequence) { + for ( + let requesting = expected_sequence; + requesting < sequence; + requesting++ + ) { + sequences_requested.push(requesting); + Byond.sendMessage('chat/resend', requesting); + } } } } diff --git a/tgui/packages/tgui-panel/chat/model.ts b/tgui/packages/tgui-panel/chat/model.ts index c39e3fda306..dbe04fadfe8 100644 --- a/tgui/packages/tgui-panel/chat/model.ts +++ b/tgui/packages/tgui-panel/chat/model.ts @@ -7,7 +7,7 @@ import { createUuid } from 'tgui-core/uuid'; import { MESSAGE_TYPE_INTERNAL, MESSAGE_TYPES } from './constants'; -import type { message, Page } from './types'; +import type { message, NewPageData, Page } from './types'; export const canPageAcceptType = (page: Page, type: string): string | boolean => type.startsWith(MESSAGE_TYPE_INTERNAL) || page.acceptedTypes[type]; @@ -46,7 +46,7 @@ export const canStoreType = ( type: string, ) => storedTypes[type]; -export const createPage = (obj?: Object): Page => { +export const createPage = (obj?: NewPageData): Page => { const acceptedTypes = {}; for (const typeDef of MESSAGE_TYPES) { @@ -66,7 +66,7 @@ export const createPage = (obj?: Object): Page => { }; export const createMainPage = (): Page => { - const acceptedTypes = {}; + const acceptedTypes: Record = {}; for (const typeDef of MESSAGE_TYPES) { acceptedTypes[typeDef.type] = true; } diff --git a/tgui/packages/tgui-panel/chat/renderer.tsx b/tgui/packages/tgui-panel/chat/renderer.tsx index 76a4e2b9c72..27943eb6381 100644 --- a/tgui/packages/tgui-panel/chat/renderer.tsx +++ b/tgui/packages/tgui-panel/chat/renderer.tsx @@ -70,7 +70,7 @@ const findNearestScrollableParent = (startingNode: HTMLElement) => { const createHighlightNode = (text: string, color: string): HTMLElement => { const node = document.createElement('span'); node.className = 'Chat__highlight'; - node.setAttribute('style', 'background-color:' + color); + node.setAttribute('style', `background-color:${color}`); node.textContent = text; return node; }; @@ -87,7 +87,7 @@ const interleaveMessage = ( color: string, ): HTMLElement => { if (interleave) { - node.setAttribute('style', 'background-color:' + color); + node.setAttribute('style', `background-color:${color}`); node.setAttribute('display', 'block'); } else { node.removeAttribute('style'); @@ -137,7 +137,7 @@ const handleImageError = (e: ErrorEvent) => { } const src = node.src; node.src = ''; - node.src = src + '#' + attempts; + node.src = `${src}#${attempts}`; node.setAttribute('data-reload-n', (attempts + 1).toString()); }, IMAGE_RETRY_DELAY); }; @@ -319,6 +319,8 @@ class ChatRenderer { const matchCase = setting.matchCase; const allowedRegex = /^[a-zа-яё0-9_\-$/^[\s\]\\]+$/gi; const regexEscapeCharacters = /[!#$%^&*)(+=.<>{}[\]:;'"|~`_\-\\/]/g; + // Reset lastIndex so it does not mess up the next word + allowedRegex.lastIndex = 0; const lines = String(text) .split(',') .map((str) => str.trim()) @@ -328,9 +330,7 @@ class ChatRenderer { str && str.length > 1 && // Must be alphanumeric (with some punctuation) - allowedRegex.test(str) && - // Reset lastIndex so it does not mess up the next word - ((allowedRegex.lastIndex = 0) || true), + allowedRegex.test(str), ); let highlightWords; let highlightRegex; @@ -338,6 +338,8 @@ class ChatRenderer { if (lines.length === 0) { return; } + // Reset lastIndex so it does not mess up the next word + allowedRegex.lastIndex = 0; const blacklistLines = String(blacklist) .split(',') .map((str) => str.trim()) @@ -347,11 +349,8 @@ class ChatRenderer { str && str.length > 1 && // Must be alphanumeric (with some punctuation) - allowedRegex.test(str) && - // Reset lastIndex so it does not mess up the next word - ((allowedRegex.lastIndex = 0) || true), + allowedRegex.test(str), ); - let blacklistWords; let blacklistregex; if (highlightBlacklist && blacklistLines.length > 0) { const blacklistRegexExpressions: string[] = []; @@ -368,7 +367,7 @@ class ChatRenderer { // We're not going to let regex characters fuck up our RegEx operation. line = line.replace(regexEscapeCharacters, '\\$&'); - blacklistRegexExpressions.push('^' + line); + blacklistRegexExpressions.push(`^${line}`); } } const regexStrBL = blacklistRegexExpressions.join('|'); @@ -376,7 +375,7 @@ class ChatRenderer { // We wrap this in a try-catch to ensure that broken regex doesn't break // the entire chat. try { - blacklistregex = new RegExp('(' + regexStrBL + ')', flagsBL); + blacklistregex = new RegExp(`(${regexStrBL})`, flagsBL); } catch { // We just reset it if it's invalid. blacklistregex = null; @@ -405,13 +404,13 @@ class ChatRenderer { } } const regexStr = regexExpressions.join('|'); - const flags = 'g' + (matchCase ? '' : 'i'); + const flags = `g${matchCase ? '' : 'i'}`; // We wrap this in a try-catch to ensure that broken regex doesn't break // the entire chat. try { // setting regex overrides matchword if (regexStr) { - highlightRegex = new RegExp('(' + regexStr + ')', flags); + highlightRegex = new RegExp(`(${regexStr})`, flags); } else { const pattern = `${matchWord ? '\\b' : ''}(${highlightWords.join( '|', @@ -649,9 +648,9 @@ class ChatRenderer { working_value = true; } else if (working_value === '$false') { working_value = false; - } else if (!isNaN(working_value)) { + } else if (!Number.isNaN(working_value)) { const parsed_float = parseFloat(working_value); - if (!isNaN(parsed_float)) { + if (!Number.isNaN(parsed_float)) { working_value = parsed_float; } } @@ -912,7 +911,7 @@ class ChatRenderer { for (let i = 0; i < cssRules.length; i++) { const rule = cssRules[i]; if (rule && typeof rule.cssText === 'string') { - cssText += rule.cssText + '\n'; + cssText += `${rule.cssText}\n`; } } } @@ -950,7 +949,7 @@ class ChatRenderer { for (const message of tmpMsgArray) { // Filter messages according to active tab for export if (this.page && canPageAcceptType(this.page, message.type)) { - messagesHtml += message.html + '\n'; + messagesHtml += `${message.html}\n`; } // if (message.node) { // messagesHtml += message.node.outerHTML + '\n'; diff --git a/tgui/packages/tgui-panel/chat/replaceInTextNode.ts b/tgui/packages/tgui-panel/chat/replaceInTextNode.ts index 8fe899e8e78..a5aa7838b89 100644 --- a/tgui/packages/tgui-panel/chat/replaceInTextNode.ts +++ b/tgui/packages/tgui-panel/chat/replaceInTextNode.ts @@ -18,13 +18,13 @@ const regexParseNode = (params: { const textLength = text.length; let nodes; let new_node; - let match; + let match = regex.exec(text); let lastIndex = 0; let fragment; let n = 0; let count = 0; // eslint-disable-next-line no-cond-assign - while ((match = regex.exec(text))) { + while (match !== null) { n += 1; // Safety check to prevent permanent // client crashing @@ -55,6 +55,7 @@ const regexParseNode = (params: { new_node = createNode(matchText); nodes.push(new_node); fragment.appendChild(new_node); + match = regex.exec(text); } if (fragment) { // Insert the remaining unmatched chunk diff --git a/tgui/packages/tgui-panel/chat/types.ts b/tgui/packages/tgui-panel/chat/types.ts index c42ed491f38..f99a31f2d8c 100644 --- a/tgui/packages/tgui-panel/chat/types.ts +++ b/tgui/packages/tgui-panel/chat/types.ts @@ -18,3 +18,9 @@ export type Page = { hideUnreadCount: boolean; createdAt: number; }; + +export type NewPageData = { + isMain: boolean; + name: string; + acceptedTypes: Record; +}; diff --git a/tgui/packages/tgui/components/NanoMap.tsx b/tgui/packages/tgui/components/NanoMap.tsx index e48592b0053..814a8dd3196 100644 --- a/tgui/packages/tgui/components/NanoMap.tsx +++ b/tgui/packages/tgui/components/NanoMap.tsx @@ -1,11 +1,12 @@ -import React, { Component, type PropsWithChildren } from 'react'; +import type React from 'react'; +import { Component, type CSSProperties, type PropsWithChildren } from 'react'; import { resolveAsset } from 'tgui/assets'; import { useBackend } from 'tgui/backend'; -import { KeyListener } from 'tgui-core/components'; import { Box, Button, Icon, + KeyListener, LabeledList, Slider, Tooltip, @@ -193,18 +194,18 @@ export class NanoMap extends Component { const WxH = this.getWxH(zoom); const mapUrl = resolveAsset(`minimap_${config.mapZLevel}.png`); - const newStyle: {} = { + const newStyle: CSSProperties = { width: `${WxH[0]}px`, height: `${WxH[1]}px`, - 'margin-top': `${offsetY}px`, - 'margin-left': `${offsetX}px`, + marginTop: `${offsetY}px`, + marginLeft: `${offsetX}px`, overflow: 'hidden', position: 'relative', - 'image-rendering': 'pixelated', - 'background-image': `url(${mapUrl})`, - 'background-size': 'cover', - 'background-repeat': 'no-repeat', - 'text-align': 'center', + imageRendering: 'pixelated', + backgroundImage: `url(${mapUrl})`, + backgroundSize: 'cover', + backgroundRepeat: 'no-repeat', + textAlign: 'center', cursor: dragging ? 'move' : 'auto', }; diff --git a/tgui/packages/tgui/interfaces/AutomatedTellerMachine.tsx b/tgui/packages/tgui/interfaces/AutomatedTellerMachine.tsx index f09e81538de..037afee9d4b 100644 --- a/tgui/packages/tgui/interfaces/AutomatedTellerMachine.tsx +++ b/tgui/packages/tgui/interfaces/AutomatedTellerMachine.tsx @@ -282,7 +282,7 @@ const CustomWithdrawal = (props: { maxLength={10} onChange={(val) => { const value = parseInt(val, 10); - if (isNaN(value)) { + if (Number.isNaN(value)) { setMoney(0); } else { setMoney(value); @@ -430,7 +430,7 @@ const TransferMenu = (props: { const [accountNum, setAccountNum] = useState(100000); const updateAccountNum = (val) => { const newVal = parseInt(val, 10); - if (isNaN(newVal)) { + if (Number.isNaN(newVal)) { setAccountNum(100000); } else { setAccountNum(newVal); @@ -440,7 +440,7 @@ const TransferMenu = (props: { const [money, setMoney] = useState(0); const updateMoney = (val) => { const newVal = parseInt(val, 10); - if (isNaN(newVal)) { + if (Number.isNaN(newVal)) { setMoney(0); } else { setMoney(newVal); diff --git a/tgui/packages/tgui/interfaces/Biogenerator.tsx b/tgui/packages/tgui/interfaces/Biogenerator.tsx index 09d42e69e79..6161c8d1c4e 100644 --- a/tgui/packages/tgui/interfaces/Biogenerator.tsx +++ b/tgui/packages/tgui/interfaces/Biogenerator.tsx @@ -43,18 +43,6 @@ export const Biogenerator = (props) => { const [sortOrder, setSortOrder] = useState('Alphabetical'); const [descending, setDescending] = useState(false); - function handleSearchText(value: string) { - setSearchText(value); - } - - function handleSortOrder(value: string) { - setSortOrder(value); - } - - function handleDescending(value: boolean) { - setDescending(value); - } - return ( @@ -82,9 +70,9 @@ export const Biogenerator = (props) => { searchText={searchText} sortOrder={sortOrder} descending={descending} - onSearchText={handleSearchText} - onSortOrder={handleSortOrder} - onDescending={handleDescending} + onSearchText={setSearchText} + onSortOrder={setSortOrder} + onDescending={setDescending} /> >; + onSortOrder: React.Dispatch>; + onDescending: React.Dispatch>; }) => { return ( diff --git a/tgui/packages/tgui/interfaces/BombTester.tsx b/tgui/packages/tgui/interfaces/BombTester.tsx index fe47e6ee2c3..5ea98af17b2 100644 --- a/tgui/packages/tgui/interfaces/BombTester.tsx +++ b/tgui/packages/tgui/interfaces/BombTester.tsx @@ -1,4 +1,4 @@ -import { Component } from 'react'; +import { Component, type CSSProperties } from 'react'; import { useBackend } from 'tgui/backend'; import { Window } from 'tgui/layouts'; import { @@ -213,7 +213,7 @@ class BombTesterSimulation extends Component { render() { const { x, y } = this.state; - const newStyle: {} = { + const newStyle: CSSProperties = { position: 'relative', left: `${x}px`, top: `${y}px`, diff --git a/tgui/packages/tgui/interfaces/Canvas.tsx b/tgui/packages/tgui/interfaces/Canvas.tsx index 84f74cbfe5f..e2de3e80bae 100644 --- a/tgui/packages/tgui/interfaces/Canvas.tsx +++ b/tgui/packages/tgui/interfaces/Canvas.tsx @@ -262,7 +262,7 @@ class PaintCanvas extends Component { this.lastHovered = coord; - const time = new Date().getTime(); + const time = Date.now(); if (this.lastSuccessfulPaint + 50 > time) { return; diff --git a/tgui/packages/tgui/interfaces/CasinoPrizeDispenser.tsx b/tgui/packages/tgui/interfaces/CasinoPrizeDispenser.tsx index 609e68f072b..6bf19e01357 100644 --- a/tgui/packages/tgui/interfaces/CasinoPrizeDispenser.tsx +++ b/tgui/packages/tgui/interfaces/CasinoPrizeDispenser.tsx @@ -33,35 +33,21 @@ export const CasinoPrizeDispenser = () => { const [sortOrder, setSortOrder] = useState('Alphabetical'); const [descending, setDescending] = useState(false); - function handleSearchText(value: string) { - setSearchText(value); - } - - function handleSortOrder(value: string) { - setSortOrder(value); - } - - function handleDescending(value: boolean) { - setDescending(value); - } - return ( - <> - - - + + ); @@ -70,9 +56,9 @@ export const CasinoPrizeDispenser = () => { const CasinoPrizeDispenserSearch = (props: { sortOrder: string; descending: boolean; - onSearchText: Function; - onSortOrder: Function; - onDescending: Function; + onSearchText: React.Dispatch>; + onSortOrder: React.Dispatch>; + onDescending: React.Dispatch>; }) => { return ( diff --git a/tgui/packages/tgui/interfaces/Changelog.tsx b/tgui/packages/tgui/interfaces/Changelog.tsx index f9f17516c55..529cb3c315c 100644 --- a/tgui/packages/tgui/interfaces/Changelog.tsx +++ b/tgui/packages/tgui/interfaces/Changelog.tsx @@ -44,16 +44,15 @@ const icons = { type Data = { dates: string[] }; -export class Changelog extends Component< - {}, - { - data: - | string - | { date: string; authors: { name: string; changes: string[] } }; - selectedDate: string; - selectedIndex: number; - } -> { +// biome-ignore lint/complexity/noBannedTypes:Ingored here +type ChangelogProps = {}; + +interface ChangelogState { + data: string | { date: string; authors: { name: string; changes: string[] } }; + selectedDate: string; + selectedIndex: number; +} +export class Changelog extends Component { dateChoices: string[]; constructor(props) { diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryList.tsx b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryList.tsx index a13d5b5df5d..f105dfa4166 100644 --- a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryList.tsx +++ b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryList.tsx @@ -8,22 +8,14 @@ import type { mobEntry } from './types'; export const CharacterDirectoryList = (props: { directory: mobEntry[]; - onOverlay: Function; + onOverlay: React.Dispatch>; }) => { const { act } = useBackend(); const { onOverlay, directory } = props; const [sortId, setSortId] = useState('name'); - const [sortOrder, setSortOrder] = useState('name'); - - function handleSortId(value: string) { - setSortId(value); - } - - function handleSortOrder(value: string) { - setSortOrder(value); - } + const [sortOrder, setSortOrder] = useState(true); return (
Name @@ -50,8 +42,8 @@ export const CharacterDirectoryList = (props: { id="species" sortId={sortId} sortOrder={sortOrder} - onSortId={handleSortId} - onSortOrder={handleSortOrder} + onSortId={setSortId} + onSortOrder={setSortOrder} > Species @@ -59,8 +51,8 @@ export const CharacterDirectoryList = (props: { id="tag" sortId={sortId} sortOrder={sortOrder} - onSortId={handleSortId} - onSortOrder={handleSortOrder} + onSortId={setSortId} + onSortOrder={setSortOrder} > Vore Tag @@ -68,8 +60,8 @@ export const CharacterDirectoryList = (props: { id="gendertag" sortId={sortId} sortOrder={sortOrder} - onSortId={handleSortId} - onSortOrder={handleSortOrder} + onSortId={setSortId} + onSortOrder={setSortOrder} > Gender @@ -77,8 +69,8 @@ export const CharacterDirectoryList = (props: { id="sexualitytag" sortId={sortId} sortOrder={sortOrder} - onSortId={handleSortId} - onSortOrder={handleSortOrder} + onSortId={setSortId} + onSortOrder={setSortOrder} > Sexuality @@ -86,8 +78,8 @@ export const CharacterDirectoryList = (props: { id="erptag" sortId={sortId} sortOrder={sortOrder} - onSortId={handleSortId} - onSortOrder={handleSortOrder} + onSortId={setSortId} + onSortOrder={setSortOrder} > ERP Tag @@ -95,8 +87,8 @@ export const CharacterDirectoryList = (props: { id="eventtag" sortId={sortId} sortOrder={sortOrder} - onSortId={handleSortId} - onSortOrder={handleSortOrder} + onSortId={setSortId} + onSortOrder={setSortOrder} > Event Pref diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectorySortButton.tsx b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectorySortButton.tsx index 24d369b5150..681629fca62 100644 --- a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectorySortButton.tsx +++ b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectorySortButton.tsx @@ -3,9 +3,9 @@ import { Button, Icon, Table } from 'tgui-core/components'; export const SortButton = (props: { id: string; sortId: string; - sortOrder: string; - onSortOrder: Function; - onSortId: Function; + sortOrder: boolean; + onSortOrder: React.Dispatch>; + onSortId: React.Dispatch>; children: React.JSX.Element | string; }) => { const { id, sortId, sortOrder, onSortOrder, onSortId, children } = props; diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryViewCharacter.tsx b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryViewCharacter.tsx index ebcb6e1423c..fc90e040619 100644 --- a/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryViewCharacter.tsx +++ b/tgui/packages/tgui/interfaces/CharacterDirectory/CharacterDirectoryViewCharacter.tsx @@ -6,7 +6,7 @@ import type { mobEntry } from './types'; export const ViewCharacter = (props: { overlay: mobEntry; - onOverlay: Function; + onOverlay: React.Dispatch>; }) => { const { overlay, onOverlay } = props; diff --git a/tgui/packages/tgui/interfaces/CharacterDirectory/index.tsx b/tgui/packages/tgui/interfaces/CharacterDirectory/index.tsx index 291df29c387..0f3665e2d7a 100644 --- a/tgui/packages/tgui/interfaces/CharacterDirectory/index.tsx +++ b/tgui/packages/tgui/interfaces/CharacterDirectory/index.tsx @@ -23,15 +23,11 @@ export const CharacterDirectory = (props) => { const [overlay, setOverlay] = useState(null); const [overwritePrefs, setOverwritePrefs] = useState(false); - function handleOverlay(value: mobEntry) { - setOverlay(value); - } - return ( {(overlay && ( - + )) || ( <>
{
)} diff --git a/tgui/packages/tgui/interfaces/CloningConsole/types.ts b/tgui/packages/tgui/interfaces/CloningConsole/types.ts index 57e0f9b7b77..6cce52f955d 100644 --- a/tgui/packages/tgui/interfaces/CloningConsole/types.ts +++ b/tgui/packages/tgui/interfaces/CloningConsole/types.ts @@ -37,5 +37,5 @@ export type modalData = { unidentity: string; strucenzymes: string; }; - modal_type: string; + type: string; }; diff --git a/tgui/packages/tgui/interfaces/ColorPickerModal.tsx b/tgui/packages/tgui/interfaces/ColorPickerModal.tsx index 02e913dede5..83ac4e2d361 100644 --- a/tgui/packages/tgui/interfaces/ColorPickerModal.tsx +++ b/tgui/packages/tgui/interfaces/ColorPickerModal.tsx @@ -6,8 +6,8 @@ import { colorList, - hexToHsva, type HsvaColor, + hexToHsva, hsvaToHex, hsvaToHslString, hsvaToRgba, @@ -47,6 +47,7 @@ interface ColorPickerData { presets: string; } +// biome-ignore lint/complexity/noBannedTypes:Ingored here type ColorPickerModalProps = {}; export const ColorPickerModal: React.FC = () => { diff --git a/tgui/packages/tgui/interfaces/Communicator/CommunicatorGeneral.tsx b/tgui/packages/tgui/interfaces/Communicator/CommunicatorGeneral.tsx index 9d6edd27e25..331299e8605 100644 --- a/tgui/packages/tgui/interfaces/Communicator/CommunicatorGeneral.tsx +++ b/tgui/packages/tgui/interfaces/Communicator/CommunicatorGeneral.tsx @@ -46,7 +46,7 @@ export const CommunicatorHeader = (props) => { export const CommunicatorFooter = (props: { videoSetting: number; - setVideoSetting: Function; + setVideoSetting: React.Dispatch>; }) => { const { act, data } = useBackend(); @@ -99,7 +99,7 @@ export const CommunicatorFooter = (props: { export const VideoComm = (props: { videoSetting: number; - setVideoSetting: Function; + setVideoSetting: React.Dispatch>; }) => { const { act, data } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/Communicator/CommunicatorMessageSubTab.tsx b/tgui/packages/tgui/interfaces/Communicator/CommunicatorMessageSubTab.tsx index 2c011d88010..010ab9c0b66 100644 --- a/tgui/packages/tgui/interfaces/Communicator/CommunicatorMessageSubTab.tsx +++ b/tgui/packages/tgui/interfaces/Communicator/CommunicatorMessageSubTab.tsx @@ -6,7 +6,7 @@ import type { Data } from './types'; export const CommunicatorMessageSubTab = (props: { clipboardMode: boolean; - onClipboardMode: Function; + onClipboardMode: React.Dispatch>; }) => { const { act, data } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/Communicator/index.tsx b/tgui/packages/tgui/interfaces/Communicator/index.tsx index 17968544cf8..e795beba331 100644 --- a/tgui/packages/tgui/interfaces/Communicator/index.tsx +++ b/tgui/packages/tgui/interfaces/Communicator/index.tsx @@ -32,10 +32,6 @@ export const Communicator = () => { const [videoSetting, setVideoSetting] = useState(0); const [clipboardMode, setClipboardMode] = useState(false); - function handleClipboardMode(value: boolean) { - setClipboardMode(value); - } - tab[tabs[0]] = ; tab[tabs[1]] = ; tab[tabs[2]] = ; @@ -43,7 +39,7 @@ export const Communicator = () => { tab[tabs[4]] = ( ); tab[tabs[5]] = ; diff --git a/tgui/packages/tgui/interfaces/CrewMonitor/CrewMonitorContent.tsx b/tgui/packages/tgui/interfaces/CrewMonitor/CrewMonitorContent.tsx index aba7fc85405..391e05892a2 100644 --- a/tgui/packages/tgui/interfaces/CrewMonitor/CrewMonitorContent.tsx +++ b/tgui/packages/tgui/interfaces/CrewMonitor/CrewMonitorContent.tsx @@ -8,8 +8,8 @@ import type { Data } from './types'; export const CrewMonitorContent = (props: { tabIndex: number; zoom: number; - onTabIndex: Function; - onZoom: Function; + onTabIndex: React.Dispatch>; + onZoom: React.Dispatch>; }) => { const { data } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/CrewMonitor/CrewMonitorMapView.tsx b/tgui/packages/tgui/interfaces/CrewMonitor/CrewMonitorMapView.tsx index 09486cf3984..ab6a77607a3 100644 --- a/tgui/packages/tgui/interfaces/CrewMonitor/CrewMonitorMapView.tsx +++ b/tgui/packages/tgui/interfaces/CrewMonitor/CrewMonitorMapView.tsx @@ -7,7 +7,7 @@ import type { Data } from './types'; export const CrewMonitorMapView = (props: { zoom: number; - onZoom: Function; + onZoom: React.Dispatch>; }) => { const { config, data } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/CrewMonitor/index.tsx b/tgui/packages/tgui/interfaces/CrewMonitor/index.tsx index a6b8e5a8c46..123f0753b9c 100644 --- a/tgui/packages/tgui/interfaces/CrewMonitor/index.tsx +++ b/tgui/packages/tgui/interfaces/CrewMonitor/index.tsx @@ -7,22 +7,14 @@ export const CrewMonitor = () => { const [tabIndex, setTabIndex] = useState(0); const [zoom, setZoom] = useState(1); - function handleTabIndex(value: number) { - setTabIndex(value); - } - - function handleZoom(value: number) { - setZoom(value); - } - return ( diff --git a/tgui/packages/tgui/interfaces/DNAModifier/types.ts b/tgui/packages/tgui/interfaces/DNAModifier/types.ts index 253bef96774..d5fdb0d6791 100644 --- a/tgui/packages/tgui/interfaces/DNAModifier/types.ts +++ b/tgui/packages/tgui/interfaces/DNAModifier/types.ts @@ -42,7 +42,7 @@ type modalData = { args: { id: string; }; - modal_type: string; + type: string; }; export type buffData = { diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/Material.tsx b/tgui/packages/tgui/interfaces/ExosuitFabricator/Material.tsx index 9e8fdbb0009..6189ce2fca5 100644 --- a/tgui/packages/tgui/interfaces/ExosuitFabricator/Material.tsx +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/Material.tsx @@ -1,3 +1,4 @@ +import type { CSSProperties } from 'react'; import { useBackend, useSharedState } from 'tgui/backend'; import { Box, @@ -11,7 +12,6 @@ import { formatMoney, formatSiUnit } from 'tgui-core/format'; import { toFixed } from 'tgui-core/math'; import { classes } from 'tgui-core/react'; import { toTitleCase } from 'tgui-core/string'; - import { MATERIAL_KEYS } from './constants'; import type { Data, material } from './types'; @@ -111,7 +111,7 @@ export const MaterialAmount = (props: { formatsi?: boolean; formatmoney?: boolean; color?: string; - style?: {}; + style?: CSSProperties; }) => { const { name, amount, formatsi, formatmoney, color, style } = props; diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/Queue.tsx b/tgui/packages/tgui/interfaces/ExosuitFabricator/Queue.tsx index 03ffef1cfbc..b1f02ce78a7 100644 --- a/tgui/packages/tgui/interfaces/ExosuitFabricator/Queue.tsx +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/Queue.tsx @@ -120,7 +120,7 @@ const QueueList = (props: { textColors: Record }) => { const { queue = [] } = data; if (!queue || !queue.length) { - return <>No parts in queue.; + return 'No parts in queue.'; } return queue.map((part, index) => ( diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/functions.ts b/tgui/packages/tgui/interfaces/ExosuitFabricator/functions.ts index 6449d52d9df..818d3daee05 100644 --- a/tgui/packages/tgui/interfaces/ExosuitFabricator/functions.ts +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/functions.ts @@ -2,7 +2,7 @@ import { uniqBy } from 'es-toolkit'; import { createSearch } from 'tgui-core/string'; import { COLOR_AVERAGE, COLOR_BAD, COLOR_NONE } from './constants'; -import type { material, part, queueFormat } from './types'; +import type { MatFormat, material, part, queueFormat } from './types'; export function materialArrayToObj( materials: material[], @@ -55,13 +55,13 @@ export function partCondFormat( } export function queueCondFormat( - materials: material | {}, + materials: Record, queue: part[] | null, ): queueFormat { - const materialTally = {}; - const matFormat = {}; - const missingMatTally = {}; - const textColors = {}; + const materialTally: Record = {}; + const matFormat: Record = {}; + const missingMatTally: Record = {}; + const textColors: Record = {}; queue?.forEach((part, i) => { textColors[i] = COLOR_NONE; diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator/types.ts b/tgui/packages/tgui/interfaces/ExosuitFabricator/types.ts index 6a5aecb5a74..18f471a68f0 100644 --- a/tgui/packages/tgui/interfaces/ExosuitFabricator/types.ts +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator/types.ts @@ -35,8 +35,10 @@ export type material = { export type queueFormat = { materialTally: Record; missingMatTally: Record; - matFormat: { color: number; deficit: number } | {}; + matFormat: Record; textColors: Record; }; +export type MatFormat = { color: number; deficit: number }; + export type internalPart = Required; diff --git a/tgui/packages/tgui/interfaces/FishingMinigame.tsx b/tgui/packages/tgui/interfaces/FishingMinigame.tsx index a2aa7579628..66a8dc061b5 100644 --- a/tgui/packages/tgui/interfaces/FishingMinigame.tsx +++ b/tgui/packages/tgui/interfaces/FishingMinigame.tsx @@ -270,10 +270,6 @@ type MouseTrackerProps = PropsWithChildren<{ }>; export class MouseTracker extends Component { - constructor(props: MouseTrackerProps) { - super(props); - } - onMouseDown = (e) => { if (this.props.onMouseDown) { this.props.onMouseDown(e); diff --git a/tgui/packages/tgui/interfaces/GhostSpawn/GhostJoin/GhostJoin.tsx b/tgui/packages/tgui/interfaces/GhostSpawn/GhostJoin/GhostJoin.tsx index 5120c00be94..7fbad340d34 100644 --- a/tgui/packages/tgui/interfaces/GhostSpawn/GhostJoin/GhostJoin.tsx +++ b/tgui/packages/tgui/interfaces/GhostSpawn/GhostJoin/GhostJoin.tsx @@ -170,7 +170,7 @@ export const GhostJoin = (props: { all_ghost_join_options: GhostJoinData }) => {
-
+
{specialRoles.map((role) => ( + act(action)} > - {'Become ' + title + '?'} + {`Become ${title}?`} diff --git a/tgui/packages/tgui/interfaces/GhostSpawn/functions.ts b/tgui/packages/tgui/interfaces/GhostSpawn/functions.ts index fc39100f67f..58621aab296 100644 --- a/tgui/packages/tgui/interfaces/GhostSpawn/functions.ts +++ b/tgui/packages/tgui/interfaces/GhostSpawn/functions.ts @@ -1,4 +1,4 @@ -import type { describeReturnData, DroneData, MouseData } from './types'; +import type { DroneData, describeReturnData, MouseData } from './types'; export function describeMouseData( data: MouseData, @@ -86,23 +86,20 @@ export function describeSpecialData( respawn: string, action: string, ): describeReturnData { - const text = 'Span as ' + role.toLowerCase() + '.'; + const text = `Span as ${role.toLowerCase()}.`; const returnData = { text: text, state: true, name: role, action: action }; if (banned) { - returnData.text = - 'You are banned from playing as ' + role.toLowerCase() + '.'; + returnData.text = `You are banned from playing as ${role.toLowerCase()}.`; returnData.state = false; return returnData; } if (!spawn_exists) { - returnData.text = - 'There are no available ' + role.toLowerCase() + ' spawn points, sorry.'; + returnData.text = `There are no available ${role.toLowerCase()} spawn points, sorry.`; returnData.state = false; return returnData; } if (respawn) { - returnData.text = - 'You must wait ' + respawn + ' before being able to respawn again.'; + returnData.text = `You must wait ${respawn} before being able to respawn again.`; returnData.state = false; return returnData; } diff --git a/tgui/packages/tgui/interfaces/ICAssembly/Plane.tsx b/tgui/packages/tgui/interfaces/ICAssembly/Plane.tsx index d1a068e571c..b5c03374284 100644 --- a/tgui/packages/tgui/interfaces/ICAssembly/Plane.tsx +++ b/tgui/packages/tgui/interfaces/ICAssembly/Plane.tsx @@ -17,6 +17,7 @@ import { PortTypesToColor, } from './types'; +// biome-ignore lint/complexity/noBannedTypes:Ingored here export type PlaneProps = {}; type PlaneState = { @@ -72,8 +73,8 @@ export class Plane extends Component { const position = this.getPosition(dom); if ( - isNaN(position.x) || - isNaN(position.y) || + Number.isNaN(position.x) || + Number.isNaN(position.y) || (lastPosition && lastPosition.x === position.x && lastPosition.y === position.y) diff --git a/tgui/packages/tgui/interfaces/LawManager.tsx b/tgui/packages/tgui/interfaces/LawManager.tsx index b2dfd66ef9f..8a18c9a4093 100644 --- a/tgui/packages/tgui/interfaces/LawManager.tsx +++ b/tgui/packages/tgui/interfaces/LawManager.tsx @@ -465,7 +465,7 @@ export const LawManagerLawSets = (props: { law_sets: law_pack[]; ion_law_nr: string; searchLawName: string; - onSearchLawName: Function; + onSearchLawName: React.Dispatch>; isAdmin: BooleanLike; isMalf: BooleanLike; }) => { diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts index e68950a8382..1d9495644ff 100644 --- a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts +++ b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts @@ -63,7 +63,7 @@ export type modalData = { }[]; record: string; }; - modal_type: string; + type: string; }; type record = { diff --git a/tgui/packages/tgui/interfaces/MiningVendor.tsx b/tgui/packages/tgui/interfaces/MiningVendor.tsx index 48ef1d5a9fc..2e7b656eb0b 100644 --- a/tgui/packages/tgui/interfaces/MiningVendor.tsx +++ b/tgui/packages/tgui/interfaces/MiningVendor.tsx @@ -34,18 +34,6 @@ export const MiningVendor = (props) => { const [sortOrder, setSortOrder] = useState('Alphabetical'); const [descending, setDescending] = useState(false); - function handleSearchText(value: string) { - setSearchText(value); - } - - function handleSortOrder(value: string) { - setSortOrder(value); - } - - function handleDescending(value: boolean) { - setDescending(value); - } - return ( @@ -54,9 +42,9 @@ export const MiningVendor = (props) => { searchText={searchText} sortOrder={sortOrder} descending={descending} - onSearchText={handleSearchText} - onSortOrder={handleSortOrder} - onDescending={handleDescending} + onSearchText={setSearchText} + onSortOrder={setSortOrder} + onDescending={setDescending} /> >; + onSortOrder: React.Dispatch>; + onDescending: React.Dispatch>; }) => { return ( diff --git a/tgui/packages/tgui/interfaces/MobSpawner.tsx b/tgui/packages/tgui/interfaces/MobSpawner.tsx index e2596c7c33e..8c91bdefae8 100644 --- a/tgui/packages/tgui/interfaces/MobSpawner.tsx +++ b/tgui/packages/tgui/interfaces/MobSpawner.tsx @@ -57,65 +57,41 @@ export const MobSpawner = (props) => { const [sizeMultiplier, setSizeMultiplier] = useState(100); const [amount, setAmount] = useState(1); - function handleHealth(value: number) { + function handleHealth(value: number): void { data.health = value; renderData(value); } - function handleMaxHealth(value: number) { + function handleMaxHealth(value: number): void { data.max_health = value; renderData(value); } - function handleMeleeDamageLower(value: number) { + function handleMeleeDamageLower(value: number): void { data.melee_damage_lower = value; renderData(value); } - function handleMeleeDamageupper(value: number) { + function handleMeleeDamageupper(value: number): void { data.melee_damage_upper = value; renderData(value); } - function handleName(value: string) { + function handleName(value: string): void { data.path_name = value; renderData(value); } - function handleDesc(value: string) { + function handleDesc(value: string): void { data.desc = value; renderData(value); } - function handleFlavor(value: string) { + function handleFlavor(value: string): void { data.flavor_text = value; renderData(value); } - function handleRadius(value: number) { - setRadius(value); - } - - function handleX(value: number) { - setX(value); - } - - function handleY(value: number) { - setY(value); - } - - function handleZ(value: number) { - setZ(value); - } - - function handleSizeMultiplier(value: number) { - setSizeMultiplier(value); - } - - function handleAmount(value: number) { - setAmount(value); - } - const tabs: React.JSX.Element[] = []; tabs[0] = ( @@ -126,7 +102,7 @@ export const MobSpawner = (props) => { z={z} sizeMultiplier={sizeMultiplier} amount={amount} - onRadius={handleRadius} + onRadius={setRadius} onHealth={handleHealth} onMaxHealth={handleMaxHealth} onMeleeDamageLower={handleMeleeDamageLower} @@ -134,11 +110,11 @@ export const MobSpawner = (props) => { onName={handleName} onDesc={handleDesc} onFlavor={handleFlavor} - onX={handleX} - onY={handleY} - onZ={handleZ} - onSizeMultiplier={handleSizeMultiplier} - onAmount={handleAmount} + onX={setX} + onY={setY} + onZ={setZ} + onSizeMultiplier={setSizeMultiplier} + onAmount={setAmount} /> ); tabs[1] = ; @@ -167,19 +143,19 @@ const GeneralMobSettings = (props: { z: number; sizeMultiplier: number; amount: number; - onRadius: Function; - onHealth: Function; - onMaxHealth: Function; - onMeleeDamageLower: Function; - onMeleeDamageUpper: Function; - onName: Function; - onDesc: Function; - onFlavor: Function; - onX: Function; - onY: Function; - onZ: Function; - onSizeMultiplier: Function; - onAmount: Function; + onRadius: React.Dispatch>; + onHealth: React.Dispatch>; + onMaxHealth: React.Dispatch>; + onMeleeDamageLower: React.Dispatch>; + onMeleeDamageUpper: React.Dispatch>; + onName: React.Dispatch>; + onDesc: React.Dispatch>; + onFlavor: React.Dispatch>; + onX: React.Dispatch>; + onY: React.Dispatch>; + onZ: React.Dispatch>; + onSizeMultiplier: React.Dispatch>; + onAmount: React.Dispatch>; }) => { const { act, data } = useBackend(); return ( diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotAccess.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotAccess.tsx index dc0685c7cc8..eed60470ba6 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotAccess.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotAccess.tsx @@ -121,7 +121,7 @@ export const ModifyRobotAccess = (props: { const AccessSection = (props: { title: string; searchText: string; - onSearchText: Function; + onSearchText: React.Dispatch>; access: Access[]; action: string; buttonColor: string; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx index 4233580f5fe..b2e4f8a9531 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx @@ -218,7 +218,7 @@ export const ModifyRobotComponent = (props: { const ComponentSection = (props: { title: string; searchText: string; - onSearchText: Function; + onSearchText: React.Dispatch>; components: Component[]; action: string; buttonColor: string; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx index 12232d4df62..f353efe8604 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx @@ -127,7 +127,7 @@ const SelectionField = (props: { previewImage: string | undefined; previewImageSize: string | undefined; searchText: string; - onSearchText: Function; + onSearchText: React.Dispatch>; action: string; buttonIcon: string; buttonColor: string; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx index dc3a404cfbc..309b4fef139 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx @@ -67,7 +67,7 @@ export const ModifyRobotRadio = (props: { target: Target }) => { const RadioSection = (props: { title: string; searchText: string; - onSearchText: Function; + onSearchText: React.Dispatch>; channels: string[]; action: string; buttonColor: string; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx index d85a6fefd82..41133fad591 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx @@ -118,7 +118,7 @@ export const ModifyRobotUpgrades = (props: { target: Target }) => { const UpgradeSection = (props: { title: string; searchText: string; - onSearchText: Function; + onSearchText: React.Dispatch>; upgrades: Upgrade[]; action: string; }) => { diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterMainMenu.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterMainMenu.tsx index 4b9255cb466..d0a4e11554a 100644 --- a/tgui/packages/tgui/interfaces/Newscaster/NewscasterMainMenu.tsx +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterMainMenu.tsx @@ -11,7 +11,9 @@ import { } from './constants'; import type { Data } from './types'; -export const NewscasterMainMenu = (props: { setScreen: Function }) => { +export const NewscasterMainMenu = (props: { + setScreen: React.Dispatch>; +}) => { const { data } = useBackend(); const { securityCaster, wanted_issue } = data; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewChannel.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewChannel.tsx index 976a8cd5707..bb59ad4f3df 100644 --- a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewChannel.tsx +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewChannel.tsx @@ -5,7 +5,9 @@ import { decodeHtmlEntities } from 'tgui-core/string'; import { NEWSCASTER_SCREEN_MAIN } from './constants'; import type { Data } from './types'; -export const NewscasterNewChannel = (props: { setScreen: Function }) => { +export const NewscasterNewChannel = (props: { + setScreen: React.Dispatch>; +}) => { const { act, data } = useBackend(); const { channel_name, c_locked, user } = data; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewStory.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewStory.tsx index 2c05065af1a..34d3ddab025 100644 --- a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewStory.tsx +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewStory.tsx @@ -4,7 +4,9 @@ import { Button, LabeledList, Section, Stack } from 'tgui-core/components'; import { NEWSCASTER_SCREEN_MAIN } from './constants'; import type { Data } from './types'; -export const NewscasterNewStory = (props: { setScreen: Function }) => { +export const NewscasterNewStory = (props: { + setScreen: React.Dispatch>; +}) => { const { act, data } = useBackend(); const { channel_name, user, title, msg, photo_data } = data; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewWanted.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewWanted.tsx index 83c3bd47b54..e9a3e6a2c1d 100644 --- a/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewWanted.tsx +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterNewWanted.tsx @@ -5,7 +5,9 @@ import { decodeHtmlEntities } from 'tgui-core/string'; import { NEWSCASTER_SCREEN_MAIN } from './constants'; import type { Data } from './types'; -export const NewscasterNewWanted = (props: { setScreen: Function }) => { +export const NewscasterNewWanted = (props: { + setScreen: React.Dispatch>; +}) => { const { act, data } = useBackend(); const { channel_name, msg, photo_data, user, wanted_issue } = data; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterPrint.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterPrint.tsx index b30b77ee19f..05fe8d0907d 100644 --- a/tgui/packages/tgui/interfaces/Newscaster/NewscasterPrint.tsx +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterPrint.tsx @@ -4,7 +4,9 @@ import { Box, Button, LabeledList, Section } from 'tgui-core/components'; import { NEWSCASTER_SCREEN_MAIN } from './constants'; import type { Data } from './types'; -export const NewscasterPrint = (props: { setScreen: Function }) => { +export const NewscasterPrint = (props: { + setScreen: React.Dispatch>; +}) => { const { act, data } = useBackend(); const { total_num, active_num, message_num, paper_remaining } = data; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewList.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewList.tsx index 4c3f73dbb3d..4977ce6142d 100644 --- a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewList.tsx +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewList.tsx @@ -8,7 +8,9 @@ import { } from './constants'; import type { Data } from './types'; -export const NewscasterViewList = (props: { setScreen: Function }) => { +export const NewscasterViewList = (props: { + setScreen: React.Dispatch>; +}) => { const { act, data } = useBackend(); const { channels } = data; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewSelected.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewSelected.tsx index 8852b2fea1b..8797b748a8d 100644 --- a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewSelected.tsx +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewSelected.tsx @@ -12,7 +12,9 @@ import { decodeHtmlEntities } from 'tgui-core/string'; import { NEWSCASTER_SCREEN_VIEWLIST } from './constants'; import type { Data } from './types'; -export const NewscasterViewSelected = (props: { setScreen: Function }) => { +export const NewscasterViewSelected = (props: { + setScreen: React.Dispatch>; +}) => { const { act, data } = useBackend(); const { viewing_channel, securityCaster, company } = data; diff --git a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewWanted.tsx b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewWanted.tsx index 7124f553873..f22a1e43f00 100644 --- a/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewWanted.tsx +++ b/tgui/packages/tgui/interfaces/Newscaster/NewscasterViewWanted.tsx @@ -5,7 +5,9 @@ import { decodeHtmlEntities } from 'tgui-core/string'; import { NEWSCASTER_SCREEN_MAIN } from './constants'; import type { Data } from './types'; -export const NewscasterViewWanted = (props: { setScreen: Function }) => { +export const NewscasterViewWanted = (props: { + setScreen: React.Dispatch>; +}) => { const { data } = useBackend(); const { wanted_issue } = data; diff --git a/tgui/packages/tgui/interfaces/NtosCrewMonitor.tsx b/tgui/packages/tgui/interfaces/NtosCrewMonitor.tsx index 038a03b7d56..980c877e2c9 100644 --- a/tgui/packages/tgui/interfaces/NtosCrewMonitor.tsx +++ b/tgui/packages/tgui/interfaces/NtosCrewMonitor.tsx @@ -7,21 +7,14 @@ export const NtosCrewMonitor = () => { const [tabIndex, setTabIndex] = useState(0); const [zoom, setZoom] = useState(1); - function handleTabIndex(value) { - setTabIndex(value); - } - - function handleZoom(value) { - setZoom(value); - } return ( diff --git a/tgui/packages/tgui/interfaces/NtosFileManager.tsx b/tgui/packages/tgui/interfaces/NtosFileManager.tsx index 56eee693edd..661e160d7e0 100644 --- a/tgui/packages/tgui/interfaces/NtosFileManager.tsx +++ b/tgui/packages/tgui/interfaces/NtosFileManager.tsx @@ -71,16 +71,18 @@ export const NtosFileManager = (props) => { act('PRG_copytousb', { uid: file })} - onDelete={(file: file) => act('PRG_deletefile', { uid: file })} - onOpen={(file: file) => act('PRG_openfile', { uid: file })} - onRename={(file: file, newName: string) => + onUpload={(file: number) => act('PRG_copytousb', { uid: file })} + onDelete={(file: number) => + act('PRG_deletefile', { uid: file }) + } + onOpen={(file: number) => act('PRG_openfile', { uid: file })} + onRename={(file: number, newName: string) => act('PRG_rename', { uid: file, new_name: newName, }) } - onDuplicate={(file: file) => act('PRG_clone', { uid: file })} + onDuplicate={(file: number) => act('PRG_clone', { uid: file })} />
{(usbconnected && ( @@ -89,20 +91,22 @@ export const NtosFileManager = (props) => { usbmode files={usbfiles} usbconnected={usbconnected} - onUpload={(file: file) => + onUpload={(file: number) => act('PRG_copyfromusb', { uid: file }) } - onDelete={(file: file) => + onDelete={(file: number) => act('PRG_deletefile', { uid: file }) } - onOpen={(file: file) => act('PRG_openfile', { uid: file })} - onRename={(file: file, newName: string) => + onOpen={(file: number) => act('PRG_openfile', { uid: file })} + onRename={(file: number, newName: string) => act('PRG_rename', { uid: file, new_name: newName, }) } - onDuplicate={(file: file) => act('PRG_clone', { uid: file })} + onDuplicate={(file: number) => + act('PRG_clone', { uid: file }) + } />
)) || @@ -140,11 +144,11 @@ const FileTable = (props: { files: file[]; usbconnected: BooleanLike; usbmode?: boolean; - onUpload: Function; - onDelete: Function; - onRename: Function; - onOpen: Function; - onDuplicate: Function; + onUpload: (file: number) => void; + onDelete: (file: number) => void; + onRename: (file: number, newName: string) => void; + onOpen: (file: number) => void; + onDuplicate: (file: number) => void; }) => { const { files = [], diff --git a/tgui/packages/tgui/interfaces/ParticleEdit/EntriesBasic.tsx b/tgui/packages/tgui/interfaces/ParticleEdit/EntriesBasic.tsx index 3234d3b46bd..84de76f9075 100644 --- a/tgui/packages/tgui/interfaces/ParticleEdit/EntriesBasic.tsx +++ b/tgui/packages/tgui/interfaces/ParticleEdit/EntriesBasic.tsx @@ -190,7 +190,9 @@ export const EntryGradient = (props: EntryGradientProps) => { var_mod: P_DATA_GRADIENT, new_value: gradient!.map((x, i) => { const floatNum = parseFloat(value); - const result = isNaN(floatNum) ? value : floatNum; + const result = Number.isNaN(floatNum) + ? value + : floatNum; return i === index ? result : x; }), }) diff --git a/tgui/packages/tgui/interfaces/Pda/index.tsx b/tgui/packages/tgui/interfaces/Pda/index.tsx index c87e5007692..fafd6409b40 100644 --- a/tgui/packages/tgui/interfaces/Pda/index.tsx +++ b/tgui/packages/tgui/interfaces/Pda/index.tsx @@ -71,16 +71,12 @@ export const Pda = (props) => { const [settingsMode, setSettingsMode] = useState(false); - function handleSettingsMode(value: BooleanLike) { - setSettingsMode(value); - } - return ( {(settingsMode && ) || (
{
)} - +
); @@ -104,7 +100,7 @@ export const Pda = (props) => { const PDAHeader = (props: { settingsMode: BooleanLike; - onSettingsMode: Function; + onSettingsMode: React.Dispatch>; }) => { const { act, data } = useBackend(); @@ -181,7 +177,9 @@ const PDASettings = (props) => { ); }; -const PDAFooter = (props: { onSettingsMode: Function }) => { +const PDAFooter = (props: { + onSettingsMode: React.Dispatch>; +}) => { const { act, data } = useBackend(); const { app, useRetro } = data; diff --git a/tgui/packages/tgui/interfaces/Pda/pda_screens/pda_atmos_scan.tsx b/tgui/packages/tgui/interfaces/Pda/pda_screens/pda_atmos_scan.tsx index f61427698eb..a519a1564d0 100644 --- a/tgui/packages/tgui/interfaces/Pda/pda_screens/pda_atmos_scan.tsx +++ b/tgui/packages/tgui/interfaces/Pda/pda_screens/pda_atmos_scan.tsx @@ -16,7 +16,13 @@ type aircontent = { bad_high: number; }; -const getItemColor = (value, min2, min1, max1, max2) => { +const getItemColor = ( + value: number, + min2: number, + min1: number, + max1: number, + max2: number, +) => { if (value < min2) { return 'bad'; } else if (value < min1) { @@ -49,7 +55,7 @@ export const pda_atmos_scan = (props) => { key={item.entry} label={item.entry} color={getItemColor( - item.val, + Number(item.val), item.bad_low, item.poor_low, item.poor_high, diff --git a/tgui/packages/tgui/interfaces/Pda/pda_screens/pda_messenger.tsx b/tgui/packages/tgui/interfaces/Pda/pda_screens/pda_messenger.tsx index 7d1853ebdb6..1215f37e558 100644 --- a/tgui/packages/tgui/interfaces/Pda/pda_screens/pda_messenger.tsx +++ b/tgui/packages/tgui/interfaces/Pda/pda_screens/pda_messenger.tsx @@ -41,14 +41,6 @@ type message = { target: string; }; -// Really cursed old API that was deprecated before IE8 but still works in IE11 because lol lmao -type IeWindow = Window & - typeof globalThis & { - clipboardData: { - setData: (type: 'Text', text: string) => {}; - }; - }; - const CopyToClipboardButton = (props: { messages: message[] }) => { const [showCompletion, setShowCompletion] = useState(false); diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/PageButton.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/PageButton.tsx index a3beb91c3c0..c13f7ca2543 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/PageButton.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/PageButton.tsx @@ -1,7 +1,7 @@ import type { ReactNode } from 'react'; import { Button } from 'tgui-core/components'; -export const PageButton =

(props: { +export const PageButton = (props: { currentPage: P; page: P; otherActivePages?: P[]; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/helper_components.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/helper_components.tsx index 3ab0c4eed8e..291464db70b 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/helper_components.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/helper_components.tsx @@ -1,4 +1,4 @@ -import React, { +import { type PropsWithChildren, type ReactNode, useCallback, diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/occupation/data.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/occupation/data.ts index de003997def..b4180cf508d 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/occupation/data.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/bay_prefs/occupation/data.ts @@ -38,5 +38,5 @@ export type OccupationData = { jobs: Record; }; -export type OccupationDataStatic = {}; -export type OccupationDataConstant = {}; +export type OccupationDataStatic = undefined; +export type OccupationDataConstant = undefined; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx index 6130794a6b1..eeb912e6402 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/base.tsx @@ -5,7 +5,6 @@ import { useEffect, useState, } from 'react'; -import React from 'react'; import { type sendAct, useBackend } from 'tgui/backend'; import { Box, diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiChemList.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiChemList.tsx index 9e21aea2915..0e3670ff93a 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiChemList.tsx +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiChemList.tsx @@ -34,34 +34,32 @@ export const ChemicalReactionList = (props: { return ( <> - <> - - - - {instant_reactions ? ( - Array.isArray(instant_reactions) ? ( - instant_reactions.map((reactionTypes, index) => - getReactionComponents(reactionTypes, 'Breakdown', index + 1), - ) - ) : ( - Object.keys(instant_reactions).map((reaction) => - getReactionComponents( - instant_reactions[reaction], - 'Breakdown', - 1, - ), - ) + + + + {instant_reactions ? ( + Array.isArray(instant_reactions) ? ( + instant_reactions.map((reactionTypes, index) => + getReactionComponents(reactionTypes, 'Breakdown', index + 1), ) ) : ( - - )} - - - + Object.keys(instant_reactions).map((reaction) => + getReactionComponents( + instant_reactions[reaction], + 'Breakdown', + 1, + ), + ) + ) + ) : ( + + )} + + {!!distilled_reactions && ( <> @@ -173,25 +171,23 @@ function getReactionComponents( )} {(!!reactionTypes.require_xgm_gas || !!reactionTypes.rejects_xgm_gas) && } - {!!reactionTypes.required && !!reactionTypes.required.length && ( - <> - {reactionTypes.required.map((required) => ( - - {!!reactionTypes.is_slime && ( - <> - - {capitalize(reactionTypes.is_slime)} - - - - )} - - {required} - - - ))} - - )} + {!!reactionTypes.required && + !!reactionTypes.required.length && + reactionTypes.required.map((required) => ( + + {!!reactionTypes.is_slime && ( + <> + + {capitalize(reactionTypes.is_slime)} + + + + )} + + {required} + + + ))} {!!reactionTypes.inhibitor && !!reactionTypes.inhibitor.length && ( <> diff --git a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiColorIcon.tsx b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiColorIcon.tsx index 80a9f703fc2..f9da2a19a7d 100644 --- a/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiColorIcon.tsx +++ b/tgui/packages/tgui/interfaces/PublicLibraryWiki/WikiCommon/WikiColorIcon.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { Box, Icon } from 'tgui-core/components'; export const getImage = async (url: string): Promise => { diff --git a/tgui/packages/tgui/interfaces/RCON/RCONSmesList.tsx b/tgui/packages/tgui/interfaces/RCON/RCONSmesList.tsx index b6faf8d3d20..4c0f870274d 100644 --- a/tgui/packages/tgui/interfaces/RCON/RCONSmesList.tsx +++ b/tgui/packages/tgui/interfaces/RCON/RCONSmesList.tsx @@ -1,6 +1,6 @@ +import type { ReactNode } from 'react'; import { useBackend } from 'tgui/backend'; import { Button, Section, Stack } from 'tgui-core/components'; - import { SMESItem } from './RCONSMESItem'; import type { Data } from './types'; @@ -9,7 +9,7 @@ export const RCONSmesList = (props) => { const { smes_info, pages, current_page } = data; - const runCallback = (cb: Function) => { + const runCallback = (cb: () => ReactNode) => { return cb(); }; diff --git a/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitHardware.tsx b/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitHardware.tsx index 0e6a85e5234..49c65392aad 100644 --- a/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitHardware.tsx +++ b/tgui/packages/tgui/interfaces/RIGSuit/RIGSuitHardware.tsx @@ -104,11 +104,8 @@ export const RIGSuitHardware = (props) => { > { const ResearchServer = (props: { server: server; - setSelectedServer: Function; + setSelectedServer: React.Dispatch>; }) => { const { data } = useBackend(); const { badmin } = data; diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/types.ts b/tgui/packages/tgui/interfaces/SecurityRecords/types.ts index 350b5544a26..b4a16d48f4e 100644 --- a/tgui/packages/tgui/interfaces/SecurityRecords/types.ts +++ b/tgui/packages/tgui/interfaces/SecurityRecords/types.ts @@ -41,6 +41,7 @@ type record = { export type modalData = { id: string; text: string; + // biome-ignore lint/complexity/noBannedTypes: In this case we got any type of Object args: {}; - modal_type: string; + type: string; }; diff --git a/tgui/packages/tgui/interfaces/SmartVend.tsx b/tgui/packages/tgui/interfaces/SmartVend.tsx index 909dfa98204..e37f6221c75 100644 --- a/tgui/packages/tgui/interfaces/SmartVend.tsx +++ b/tgui/packages/tgui/interfaces/SmartVend.tsx @@ -34,18 +34,6 @@ export const SmartVend = (props) => { const [sortOrder, setSortOrder] = useState('Alphabetical'); const [descending, setDescending] = useState(false); - function handleSearchText(value: string) { - setSearchText(value); - } - - function handleSortOrder(value: string) { - setSortOrder(value); - } - - function handleDescending(value: boolean) { - setDescending(value); - } - const { secure, locked, contents } = data; return ( @@ -55,7 +43,7 @@ export const SmartVend = (props) => { {(secure && locked === -1 && ( - Sec.re ACC_** //):securi_nt.diag=>##'or 1=1'%($... + {`Sec.re ACC_** //):securi_nt.diag=>##'or 1=1'%($...`} )) || @@ -73,9 +61,9 @@ export const SmartVend = (props) => { searchText={searchText} sortOrder={sortOrder} descending={descending} - onSearchText={handleSearchText} - onSortOrder={handleSortOrder} - onDescending={handleDescending} + onSearchText={setSearchText} + onSortOrder={setSortOrder} + onDescending={setDescending} /> >; + onSortOrder: React.Dispatch>; + onDescending: React.Dispatch>; }) => { const { searchText, diff --git a/tgui/packages/tgui/interfaces/SuitCycler.tsx b/tgui/packages/tgui/interfaces/SuitCycler.tsx index cfa786e816b..ff3aaa29695 100644 --- a/tgui/packages/tgui/interfaces/SuitCycler.tsx +++ b/tgui/packages/tgui/interfaces/SuitCycler.tsx @@ -42,20 +42,12 @@ export const SuitCycler = (props) => { (!!species && species[0]) || undefined, ); - function handleSelectedDepartment(value: string | undefined) { - setSelectedDepartment(value); - } - - function handleSelectedSpecies(value: string | undefined) { - setSelectedSpecies(value); - } - let subTemplate = ( ); @@ -77,8 +69,10 @@ export const SuitCycler = (props) => { const SuitCyclerContent = (props: { selectedDepartment: string | undefined; selectedSpecies: string | undefined; - onSelectedDepartment: Function; - onSelectedSpecies: Function; + onSelectedDepartment: React.Dispatch< + React.SetStateAction + >; + onSelectedSpecies: React.Dispatch>; }) => { const { act, data } = useBackend(); const { diff --git a/tgui/packages/tgui/interfaces/SupplyConsole/types.ts b/tgui/packages/tgui/interfaces/SupplyConsole/types.ts index 7d8bc8133b0..6877bc09dd2 100644 --- a/tgui/packages/tgui/interfaces/SupplyConsole/types.ts +++ b/tgui/packages/tgui/interfaces/SupplyConsole/types.ts @@ -24,7 +24,7 @@ export type modalData = { ref: string; random: number; }; - modal_type: string; + type: string; }; export type supplyPack = { diff --git a/tgui/packages/tgui/interfaces/Uplink/UplinkHeader.tsx b/tgui/packages/tgui/interfaces/Uplink/UplinkHeader.tsx index f7d39db0131..0b7769a5b66 100644 --- a/tgui/packages/tgui/interfaces/Uplink/UplinkHeader.tsx +++ b/tgui/packages/tgui/interfaces/Uplink/UplinkHeader.tsx @@ -5,7 +5,7 @@ import type { Data } from './types'; export const UplinkHeader = (props: { screen: number; - setScreen: Function; + setScreen: React.Dispatch>; }) => { const { data } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/Vending.tsx b/tgui/packages/tgui/interfaces/Vending.tsx index 0b19e16384b..b108c53f271 100644 --- a/tgui/packages/tgui/interfaces/Vending.tsx +++ b/tgui/packages/tgui/interfaces/Vending.tsx @@ -98,14 +98,10 @@ export const Vending = (props) => { const { panel } = data; const [searchText, setSearchText] = useState(''); - function handleSearchText(value: string) { - setSearchText(value); - } - return ( - + {panel ? : null} @@ -114,7 +110,7 @@ export const Vending = (props) => { export const VendingProducts = (props: { searchText: string; - onSearch: Function; + onSearch: React.Dispatch>; }) => { const { act, data } = useBackend(); const { coin, chargesMoney, user, userMoney, guestNotice, products } = data; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VorePanelElements/VorePanelTextArea.tsx b/tgui/packages/tgui/interfaces/VorePanel/VorePanelElements/VorePanelTextArea.tsx index ba502d6d3e5..5baeaf56b86 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/VorePanelElements/VorePanelTextArea.tsx +++ b/tgui/packages/tgui/interfaces/VorePanel/VorePanelElements/VorePanelTextArea.tsx @@ -27,18 +27,19 @@ const DescriptionSyntaxHighlighting = (props: { desc: string }) => { const regexCopy = new RegExp(SYNTAX_REGEX); let lastIndex = 0; - let result; - while ((result = regexCopy.exec(desc)) !== null) { - elements.push(<>{desc.substring(lastIndex, result.index)}); + let result = regexCopy.exec(desc); + while (result !== null) { + elements.push(desc.substring(lastIndex, result.index)); elements.push( {result[0]} , ); lastIndex = result.index + result[0].length; + result = regexCopy.exec(desc); } - elements.push(<>{desc.substring(lastIndex)}); + elements.push(desc.substring(lastIndex)); setHtmlDesc(elements); }, [desc]); @@ -49,7 +50,7 @@ const DescriptionSyntaxHighlighting = (props: { desc: string }) => { const CountedTextElement = (props: { limit: number; entry: string; - action: Function; + action: (value: string | string[], index?: number) => void; index?: number; }) => { const { entry, limit, action, index } = props; @@ -90,7 +91,7 @@ const CountedTextElement = (props: { const AreaMapper = (props: { limit: number; entry: string[]; - action: Function; + action: (value: string | string[], index?: number) => void; exactLength: boolean; maxEntries: number; }) => { @@ -163,7 +164,7 @@ export const VorePanelEditTextArea = (props: { noHighlight, } = props; - function doAct(value: string | string[]) { + function doAct(value: string | string[]): void { if (Array.isArray(value)) { act(action, { attribute: listAction, msgtype: subAction, val: value }); return; diff --git a/tgui/packages/tgui/interfaces/VorePanel/VorePanelMainTabs/VoreSelectedBelly.tsx b/tgui/packages/tgui/interfaces/VorePanel/VorePanelMainTabs/VoreSelectedBelly.tsx index 8c94d1022df..9e0f4e66569 100644 --- a/tgui/packages/tgui/interfaces/VorePanel/VorePanelMainTabs/VoreSelectedBelly.tsx +++ b/tgui/packages/tgui/interfaces/VorePanel/VorePanelMainTabs/VoreSelectedBelly.tsx @@ -124,7 +124,7 @@ export const VoreSelectedBelly = (props: { onClick={() => act('change_vore_tab', { tab: index })} > {tabToNames[index]} - {!!(index === 6) && '(' + content_length + ')'} + {!!(index === 6) && `(${content_length})`} ))} diff --git a/tgui/packages/tgui/interfaces/common/ComplexModal.tsx b/tgui/packages/tgui/interfaces/common/ComplexModal.tsx index 22ca961e3aa..88ee27c6d4a 100644 --- a/tgui/packages/tgui/interfaces/common/ComplexModal.tsx +++ b/tgui/packages/tgui/interfaces/common/ComplexModal.tsx @@ -1,15 +1,16 @@ import { type KeyboardEvent, useRef, useState } from 'react'; import { useBackend } from 'tgui/backend'; -import { Modal } from 'tgui-core/components'; import { Box, Button, Dropdown, Image, Input, + Modal, Stack, } from 'tgui-core/components'; +// biome-ignore lint/complexity/noBannedTypes: In this case, we got any type of Object type Data = { modal: { id: string; args: {}; text: string; type: string } }; const bodyOverrides = {}; @@ -39,11 +40,18 @@ export const modalOpen = (id, args = {}) => { */ export const modalRegisterBodyOverride = ( id: string, - bodyOverride: Function, + bodyOverride: (modal: { + id: string; + text: string; + // biome-ignore lint/complexity/noBannedTypes: In this case, we got any type of Object + args: {}; + type: string; + }) => React.JSX.Element, ) => { bodyOverrides[id] = bodyOverride; }; +// biome-ignore lint/complexity/noBannedTypes: In this case, we got any type of Object const modalAnswer = (id: string, answer: string, args: {}) => { const { act, data } = useBackend(); diff --git a/tgui/packages/tgui/layouts/TitleBar.tsx b/tgui/packages/tgui/layouts/TitleBar.tsx index f5b63120c62..25dc90e6f3b 100644 --- a/tgui/packages/tgui/layouts/TitleBar.tsx +++ b/tgui/packages/tgui/layouts/TitleBar.tsx @@ -24,7 +24,6 @@ function statusToColor(status: number): string { return 'good'; case UI_UPDATE: return 'average'; - case UI_DISABLED: default: return 'bad'; } diff --git a/tools/StrongDMM/README.md b/tools/StrongDMM/README.md index ba8a5529012..9c550696c0f 100644 --- a/tools/StrongDMM/README.md +++ b/tools/StrongDMM/README.md @@ -1,14 +1,17 @@ # StrongDMM ### LICENSE + The contents of this folder are licensed under the GNU General Public License version 3, which can be found in full in ~/LICENSE-GPL3.txt. The source code can be found at https://github.com/SpaiR/StrongDMM ### Overview + [SpaiR/StrongDMM](https://github.com/SpaiR/StrongDMM) is a 3rd-party program licensed under GPL-v3 that loads in the object tree from a .dme file, and provides an interface very similar to DreamMaker's own mapping interface with which to make and edit .dmm map files. Generally speaking, it loads faster than DM, has several useful features and a cleaner interface, but requires compilation from a separate program (With some care required to ensure that changes are properly copied over). Executables for both Windows and Linux are provided, differentiated by the windows executable being suffixed with `.exe`. There are also instructions on StrongDMM's github page (Linked above) on how to build it from the source code (Not provided) ### Setup + Navigate to `/tools/StrongDMM` and run the launcher appropriate for your operating system. If you're on windows, it ends in `.exe`. If you're on linux, it has no suffix. Because going into those folders is considered tedious by ~~lazy coders~~ basically everyone, it's recommended to set up a shortcut in the root directory. The launcher will automatically update to the latest build and then open the editor. You should see something like this: ![.png](https://puu.sh/H75QH/28c4a5917c.png) @@ -19,8 +22,8 @@ It's important to note the format of the map files you intend to be working with You can also change the other settings as you see fit, but the map save format and nudge mode are most important. Unless you know what you're doing, you probably don't want to change nudge mode, as `step_x/step_y` breaks the commonly-used glide movement animations. Ticking the `Alternate Scrolling Behaviour` will allow you to zoom while holding Space, and scrolling otherwise pans like DreamMaker. With the option unticked, scrolling will only affect zoom. The middle mouse button can always be used to pan, in either case. - ### Loading a map + If this is the first time you're using StrongDMM, the panel on the left will be blank except for the `Open Environment...` button at the top. You'll want to click that (Or go `File`->`Open Environment`, or open one directly from `Recent Environments`) and then navigate to the `.dme` file for the project you're working on. StrongDMM needs this to load in the object tree so it can understand the map files that you try to load. It's generally a good idea to make sure that the map files you want to load successfully compile, which generally means making sure the right files for their map-specific objects and areas are ticked when you compile. Once you've loaded an environment, the panel on the left should show the object tree, which looks very similar to DreamMaker's UI, but is notably not a blinding white. ![.png](https://puu.sh/H75YM/dc455a1b42.png) @@ -34,6 +37,7 @@ If the map cannot load correctly because objects aren't defined in the environme ![.png](https://puu.sh/H763d/c609eaff27.png) ### Mapping + Once a map is loaded, you're pretty much free to start mapping, just as you would in DreamMaker. You can use Ctrl+[1, 2, 3, 4] to toggle the various layers or do so manually from the `Options` menu, which notably _doesn't_ require ticking any extra boxes. By default, in the bottom right of the screen will be one or two small UI elements. The bottommost one will show the map coordinates of the cursor, and the top one, if present, will allow you to move between Z-levels on maps with multiple Z levels (But not when multiple map _files_ are stitched together into multi-Z). ![.png](https://puu.sh/H7685/da1121bfef.png) @@ -42,4 +46,4 @@ Shift+Right Click will open up the Edit-Variables interface for whatever you cli ![.png](https://puu.sh/H76aI/0726f5ebc4.png) -The only other really important thing to note is that all these panels can be moved about the whole window, so if you find something is in the way, you're totally free to move it. And again, remember to save (Ctrl+S) and compile your changes before you start your test server and wonder where in the hells all your changes went. \ No newline at end of file +The only other really important thing to note is that all these panels can be moved about the whole window, so if you find something is in the way, you're totally free to move it. And again, remember to save (Ctrl+S) and compile your changes before you start your test server and wonder where in the hells all your changes went. diff --git a/tools/UpdatePaths/readme.md b/tools/UpdatePaths/readme.md index 6e40a73e105..23f2ce6976d 100644 --- a/tools/UpdatePaths/readme.md +++ b/tools/UpdatePaths/readme.md @@ -74,6 +74,7 @@ If you do not want any variable edits to carry over, you can simply skip adding ```txt /obj/structure/door/airlock/science/closed/rd : /obj/structure/door/airlock/science/rd/closed ``` + On this example map key: ```dm @@ -85,8 +86,8 @@ On this example map key: /turf/open/floor/iron, /area/science/rd), ``` -You will then result the following: +You will then result the following: ```dm "a" = ( @@ -134,11 +135,12 @@ Presto, like it never existed. Note how both the "a" and "b" files were able to ### Multiple Path Output -UpdatePaths has the powerful ability to output multiple paths from a single input path. Let's say that you have a snowflake turf (`/turf/open/floor/iron/i_like_spawning_mobs`) with some behavior that you atomize out into some spawner `/obj/mob_spawner` that can work on every single turf. So, let's script that out. +UpdatePaths has the powerful ability to output multiple paths from a single input path. Let's say that you have a snowflake turf (`/turf/open/floor/iron/i_like_spawning_mobs`) with some behavior that you atomize out into some spawner `/obj/mob_spawner` that can work on every single turf. So, let's script that out. ```txt /turf/open/floor/iron/i_like_spawning_mobs : /obj/mob_spawner, /turf/open/floor/iron ``` + So, now when you have the following example map keys: ```dm @@ -155,6 +157,7 @@ Running the script will mutate this into: /turf/open/floor/iron, /area/station/kitchen), ``` + Remember that this is a kind of silly example, but this is one of the things that UpdatePaths was built to do- help coders fix shitty code without having to bug out over how maps don't compile. ### Subtype Handling @@ -197,7 +200,6 @@ Running the script will update this into: Note how since you kept in `{@OLD}`, it was able to retain the re-named variables of the subtypes. - ### Old Path Variable Filtering Alright, there's a few subsections here. This is how you are able to filter out old paths to ensure you target something precise. Let's just go through them one by one. @@ -256,6 +258,7 @@ That's cool, but let's say you have this same example, but let's say that you do ```txt /mob/living/basic/mouse{name="Tom"} : /mob/living/basic/mouse/tom{pixel_x = @OLD} ``` + The following is also supported, but it's not recommended since it's harder to read because it doesn't really mesh with the TGM format: ```txt @@ -341,6 +344,7 @@ You would then get the following output: Note how we keep the "Money Hole" intact, while still managing to extrapolate the `dir` variable to 1 on the sink that had absolutely no variables set on it. This is useful for when you want to change a variable that is not shown in the map editor, but you want to keep the rest of the variables intact. #### Methods: Any Value Fits All and Naming Conventions + But what if you just want to rename the variable `maxHealth` to `good_boy_points` for all instances of `/mob/living/github_user`? Using the `@ANY` parameter after a variable name, you can capture any instance that has it edited in a map. While, to set the value of the newly named `good_boy_points` to that of the old `maxHealth`, we can use `@OLD:maxHealth`, put after the name of the new variable to achieve that. The result'll be something like this: ```txt @@ -400,6 +404,7 @@ All of the examples provided within are not mutually exclusive! They can be mixe ## Why should I care? UpdatePaths is an incredible valuable tool to the following populations: + - Mappers who have mapping PRs that take a long time to create, and that will need to be updated as progression goes on. Having an UpdatePaths file makes it much more simple to get them to compile their map properly, and not lose paths. - Downstreams who have additional maps to the ones we have. You obviously can't Search & Replace fix for a whole downstream, but you can give them the ammunition (UpdatePaths script) for them to quickly and easily resolve that problem. - You! As you've seen, you can do a lot of clever and powerful tools that respect the TGM format, from Old Path Filtering to Multiple Path Output- and you can do it all with a simple text file! Otherwise, you would be stuck in absolute RegEx hell, and still end up missing on several potential edge cases. UpdatePaths is built on the same framework that builds the TGM format, so it's incredibly reliable in finding and replacing paths. diff --git a/tools/alwayson-backend/README b/tools/alwayson-backend/README index 8c9c2040935..b261f887c58 100644 --- a/tools/alwayson-backend/README +++ b/tools/alwayson-backend/README @@ -7,6 +7,4 @@ you will have to supply the correct ip-address/domain and port on where this API For this you can set the DBCONFIG_PATH environment variable (or use the .env.example) to the exact path of the config/dbconfig.txt. - - -Do not forget to rename .env.example to .env of course, if you want to use a file. \ No newline at end of file +Do not forget to rename .env.example to .env of course, if you want to use a file. diff --git a/tools/build/build.ts b/tools/build/build.ts index 0b92adf811d..98c4e7ffc1d 100644 --- a/tools/build/build.ts +++ b/tools/build/build.ts @@ -1,4 +1,5 @@ #!/usr/bin/env node + /** * Build script for /tg/station 13 codebase. * @@ -6,27 +7,27 @@ * https://github.com/stylemistake/juke-build */ -import Bun from "bun"; -import fs from "node:fs"; -import Juke from "./juke/index.js"; -import { bun } from "./lib/bun"; -import { DreamDaemon, DreamMaker, NamedVersionFile } from "./lib/byond"; -import { downloadFile } from "./lib/download"; -import { formatDeps } from "./lib/helpers"; -import { prependDefines } from "./lib/tgs"; +import fs from 'node:fs'; +import Bun from 'bun'; +import Juke from './juke/index.js'; +import { bun, bunRoot } from './lib/bun'; +import { DreamDaemon, DreamMaker, NamedVersionFile } from './lib/byond'; +import { downloadFile } from './lib/download'; +import { formatDeps } from './lib/helpers'; +import { prependDefines } from './lib/tgs'; -export const TGS_MODE = process.env.CBT_BUILD_MODE === "TGS"; +export const TGS_MODE = process.env.CBT_BUILD_MODE === 'TGS'; -export const DME_NAME = "vorestation"; +export const DME_NAME = 'vorestation'; -Juke.chdir("../..", import.meta.url); +Juke.chdir('../..', import.meta.url); -const dependencies: Record = await Bun.file("dependencies.sh") +const dependencies: Record = await Bun.file('dependencies.sh') .text() .then(formatDeps) .catch((err) => { Juke.logger.error( - "Failed to read dependencies.sh, please ensure it exists and is formatted correctly.", + 'Failed to read dependencies.sh, please ensure it exists and is formatted correctly.', ); Juke.logger.error(err); throw new Juke.ExitCode(1); @@ -35,8 +36,8 @@ const dependencies: Record = await Bun.file("dependencies.sh") // Canonical path for the cutter exe at this moment function getCutterPath() { const ver = dependencies.CUTTER_VERSION; - const suffix = process.platform === "win32" ? ".exe" : ""; - const file_ver = ver.split(".").join("-"); + const suffix = process.platform === 'win32' ? '.exe' : ''; + const file_ver = ver.split('.').join('-'); return `tools/icon_cutter/cache/hypnagogic${file_ver}${suffix}`; } @@ -44,39 +45,39 @@ function getCutterPath() { const cutter_path = getCutterPath(); export const DefineParameter = new Juke.Parameter({ - type: "string[]", - alias: "D", + type: 'string[]', + alias: 'D', }); export const PortParameter = new Juke.Parameter({ - type: "string", - alias: "p", + type: 'string', + alias: 'p', }); export const DmVersionParameter = new Juke.Parameter({ - type: "string", + type: 'string', }); -export const CiParameter = new Juke.Parameter({ type: "boolean" }); +export const CiParameter = new Juke.Parameter({ type: 'boolean' }); export const ForceRecutParameter = new Juke.Parameter({ - type: "boolean", - name: "force-recut", + type: 'boolean', + name: 'force-recut', }); export const SkipIconCutter = new Juke.Parameter({ - type: "boolean", - name: "skip-icon-cutter", + type: 'boolean', + name: 'skip-icon-cutter', }); export const WarningParameter = new Juke.Parameter({ - type: "string[]", - alias: "W", + type: 'string[]', + alias: 'W', }); export const NoWarningParameter = new Juke.Parameter({ - type: "string[]", - alias: "I", + type: 'string[]', + alias: 'I', }); export const CutterTarget = new Juke.Target({ @@ -87,11 +88,11 @@ export const CutterTarget = new Juke.Target({ executes: async () => { const repo = dependencies.CUTTER_REPO; const ver = dependencies.CUTTER_VERSION; - const suffix = process.platform === "win32" ? ".exe" : ""; + const suffix = process.platform === 'win32' ? '.exe' : ''; const download_from = `https://github.com/${repo}/releases/download/${ver}/hypnagogic${suffix}`; await downloadFile(download_from, cutter_path); - if (process.platform !== "win32") { - await Juke.exec("chmod", ["+x", cutter_path]); + if (process.platform !== 'win32') { + await Juke.exec('chmod', ['+x', cutter_path]); } }, }); @@ -114,7 +115,7 @@ export const IconCutterTarget = new Juke.Target({ ]; return [ ...standard_inputs, - ...existing_configs.map((file) => file.replace(".toml", "")), + ...existing_configs.map((file) => file.replace('.toml', '')), ]; }, outputs: ({ get }) => { @@ -124,15 +125,15 @@ export const IconCutterTarget = new Juke.Target({ ...Juke.glob(`icons/**/*.dmi.toml`), ]; return folders - .map((file) => file.replace(`.png.toml`, ".dmi")) - .map((file) => file.replace(`.dmi.toml`, ".png")); + .map((file) => file.replace(`.png.toml`, '.dmi')) + .map((file) => file.replace(`.dmi.toml`, '.png')); }, executes: async () => { await Juke.exec(cutter_path, [ - "--dont-wait", - "--templates", - "cutter_templates", - "icons", + '--dont-wait', + '--templates', + 'cutter_templates', + 'icons', ]); }, }); @@ -140,18 +141,18 @@ export const IconCutterTarget = new Juke.Target({ export const DmMapsIncludeTarget = new Juke.Target({ executes: async () => { const folders = [ - ...Juke.glob("_maps/map_files/**/modular_pieces/*.dmm"), - ...Juke.glob("_maps/RandomRuins/**/*.dmm"), - ...Juke.glob("_maps/RandomZLevels/**/*.dmm"), - ...Juke.glob("_maps/shuttles/**/*.dmm"), - ...Juke.glob("_maps/templates/**/*.dmm"), + ...Juke.glob('_maps/map_files/**/modular_pieces/*.dmm'), + ...Juke.glob('_maps/RandomRuins/**/*.dmm'), + ...Juke.glob('_maps/RandomZLevels/**/*.dmm'), + ...Juke.glob('_maps/shuttles/**/*.dmm'), + ...Juke.glob('_maps/templates/**/*.dmm'), ]; const content = folders - .map((file) => file.replace("_maps/", "")) + .map((file) => file.replace('_maps/', '')) .map((file) => `#include "${file}"`) - .join("\n") + "\n"; - fs.writeFileSync("_maps/templates.dm", content); + .join('\n') + '\n'; + fs.writeFileSync('_maps/templates.dm', content); }, }); @@ -164,18 +165,18 @@ export const DmTarget = new Juke.Target({ SkipIconCutter, ], dependsOn: ({ get }) => [ - get(DefineParameter).includes("ALL_MAPS") && DmMapsIncludeTarget, + get(DefineParameter).includes('ALL_MAPS') && DmMapsIncludeTarget, !get(SkipIconCutter) && IconCutterTarget, ], inputs: [ - "_maps/map_files/generic/**", - "maps/**/*.dm", - "code/**", - "html/**", - "icons/**", - "interface/**", - "sound/**", - "tgui/public/tgui.html", + '_maps/map_files/generic/**', + 'maps/**/*.dm', + 'code/**', + 'html/**', + 'icons/**', + 'interface/**', + 'sound/**', + 'tgui/public/tgui.html', `${DME_NAME}.dme`, NamedVersionFile, ], @@ -187,8 +188,8 @@ export const DmTarget = new Juke.Target({ }, executes: async ({ get }) => { await DreamMaker(`${DME_NAME}.dme`, { - defines: ["CBT", ...get(DefineParameter)], - warningsAsErrors: get(WarningParameter).includes("error"), + defines: ['CBT', ...get(DefineParameter)], + warningsAsErrors: get(WarningParameter).includes('error'), ignoreWarningCodes: get(NoWarningParameter), namedDmVersion: get(DmVersionParameter), }); @@ -203,36 +204,36 @@ export const DmTestTarget = new Juke.Target({ NoWarningParameter, ], dependsOn: ({ get }) => [ - get(DefineParameter).includes("ALL_MAPS") && DmMapsIncludeTarget, + get(DefineParameter).includes('ALL_MAPS') && DmMapsIncludeTarget, IconCutterTarget, ], executes: async ({ get }) => { fs.copyFileSync(`${DME_NAME}.dme`, `${DME_NAME}.test.dme`); await DreamMaker(`${DME_NAME}.test.dme`, { - defines: ["CBT", "CIBUILDING", ...get(DefineParameter)], - warningsAsErrors: get(WarningParameter).includes("error"), + defines: ['CBT', 'CIBUILDING', ...get(DefineParameter)], + warningsAsErrors: get(WarningParameter).includes('error'), ignoreWarningCodes: get(NoWarningParameter), namedDmVersion: get(DmVersionParameter), }); - Juke.rm("data/logs/ci", { recursive: true }); + Juke.rm('data/logs/ci', { recursive: true }); const options = { dmbFile: `${DME_NAME}.test.dmb`, namedDmVersion: get(DmVersionParameter), }; await DreamDaemon( options, - "-close", - "-trusted", - "-verbose", - "-params", - "log-directory=ci", + '-close', + '-trusted', + '-verbose', + '-params', + 'log-directory=ci', ); - Juke.rm("*.test.*"); + Juke.rm('*.test.*'); try { - const cleanRun = fs.readFileSync("data/logs/ci/clean_run.lk", "utf-8"); + const cleanRun = fs.readFileSync('data/logs/ci/clean_run.lk', 'utf-8'); console.log(cleanRun); } catch (err) { - Juke.logger.error("Test run was not clean, exiting"); + Juke.logger.error('Test run was not clean, exiting'); throw new Juke.ExitCode(1); } }, @@ -246,21 +247,21 @@ export const AutowikiTarget = new Juke.Target({ NoWarningParameter, ], dependsOn: ({ get }) => [ - get(DefineParameter).includes("ALL_MAPS") && DmMapsIncludeTarget, + get(DefineParameter).includes('ALL_MAPS') && DmMapsIncludeTarget, IconCutterTarget, ], - outputs: ["data/autowiki_edits.txt"], + outputs: ['data/autowiki_edits.txt'], executes: async ({ get }) => { fs.copyFileSync(`${DME_NAME}.dme`, `${DME_NAME}.test.dme`); await DreamMaker(`${DME_NAME}.test.dme`, { - defines: ["CBT", "AUTOWIKI", ...get(DefineParameter)], - warningsAsErrors: get(WarningParameter).includes("error"), + defines: ['CBT', 'AUTOWIKI', ...get(DefineParameter)], + warningsAsErrors: get(WarningParameter).includes('error'), ignoreWarningCodes: get(NoWarningParameter), namedDmVersion: get(DmVersionParameter), }); - Juke.rm("data/autowiki_edits.txt"); - Juke.rm("data/autowiki_files", { recursive: true }); - Juke.rm("data/logs/ci", { recursive: true }); + Juke.rm('data/autowiki_edits.txt'); + Juke.rm('data/autowiki_files', { recursive: true }); + Juke.rm('data/logs/ci', { recursive: true }); const options = { dmbFile: `${DME_NAME}.test.dmb`, @@ -268,15 +269,15 @@ export const AutowikiTarget = new Juke.Target({ }; await DreamDaemon( options, - "-close", - "-trusted", - "-verbose", - "-params", - "log-directory=ci", + '-close', + '-trusted', + '-verbose', + '-params', + 'log-directory=ci', ); - Juke.rm("*.test.*"); - if (!fs.existsSync("data/autowiki_edits.txt")) { - Juke.logger.error("Autowiki did not generate an output, exiting"); + Juke.rm('*.test.*'); + if (!fs.existsSync('data/autowiki_edits.txt')) { + Juke.logger.error('Autowiki did not generate an output, exiting'); throw new Juke.ExitCode(1); } }, @@ -284,112 +285,93 @@ export const AutowikiTarget = new Juke.Target({ export const BunTarget = new Juke.Target({ parameters: [CiParameter], - inputs: ["tgui/**/package.json"], + inputs: ['tgui/**/package.json'], executes: () => { - return bun("install", "--frozen-lockfile", "--ignore-scripts"); + return bun('install', '--frozen-lockfile', '--ignore-scripts'); + }, +}); + +export const BiomeInstallTarget = new Juke.Target({ + dependsOn: [BunTarget], + inputs: ['package.json', 'bun.lock'], + onlyWhen: () => { + return Juke.glob('node_modules/@biomejs/**').length === 0; + }, + executes: () => { + return bunRoot('install'); }, }); export const TgFontTarget = new Juke.Target({ dependsOn: [BunTarget], inputs: [ - "tgui/packages/tgfont/**/*.+(js|mjs|svg)", - "tgui/packages/tgfont/package.json", + 'tgui/packages/tgfont/**/*.+(js|mjs|svg)', + 'tgui/packages/tgfont/package.json', ], outputs: [ - "tgui/packages/tgfont/dist/tgfont.css", - "tgui/packages/tgfont/dist/tgfont.woff2", + 'tgui/packages/tgfont/dist/tgfont.css', + 'tgui/packages/tgfont/dist/tgfont.woff2', ], executes: async () => { - await bun("tgfont:build"); - fs.mkdirSync("tgui/packages/tgfont/static", { recursive: true }); + await bun('tgfont:build'); + fs.mkdirSync('tgui/packages/tgfont/static', { recursive: true }); fs.copyFileSync( - "tgui/packages/tgfont/dist/tgfont.css", - "tgui/packages/tgfont/static/tgfont.css", + 'tgui/packages/tgfont/dist/tgfont.css', + 'tgui/packages/tgfont/static/tgfont.css', ); fs.copyFileSync( - "tgui/packages/tgfont/dist/tgfont.woff2", - "tgui/packages/tgfont/static/tgfont.woff2", + 'tgui/packages/tgfont/dist/tgfont.woff2', + 'tgui/packages/tgfont/static/tgfont.woff2', ); }, }); export const TguiTarget = new Juke.Target({ - dependsOn: [BunTarget], + dependsOn: [BunTarget, BiomeInstallTarget], inputs: [ - "tgui/rspack.config.ts", - "tgui/**/package.json", - "tgui/packages/**/*.+(js|cjs|ts|tsx|jsx|scss)", + 'tgui/rspack.config.ts', + 'tgui/**/package.json', + 'tgui/packages/**/*.+(js|cjs|ts|tsx|jsx|scss)', ], outputs: [ - "tgui/public/tgui.bundle.css", - "tgui/public/tgui.bundle.js", - "tgui/public/tgui-panel.bundle.css", - "tgui/public/tgui-panel.bundle.js", - "tgui/public/tgui-say.bundle.css", - "tgui/public/tgui-say.bundle.js", + 'tgui/public/tgui.bundle.css', + 'tgui/public/tgui.bundle.js', + 'tgui/public/tgui-panel.bundle.css', + 'tgui/public/tgui-panel.bundle.js', + 'tgui/public/tgui-say.bundle.css', + 'tgui/public/tgui-say.bundle.js', ], - executes: () => bun("tgui:build"), -}); - -export const TguiEslintTarget = new Juke.Target({ - parameters: [CiParameter], - dependsOn: [BunTarget], - executes: ({ get }) => bun("tgui:lint", !get(CiParameter) && "--fix"), -}); - -export const TguiPrettierTarget = new Juke.Target({ - dependsOn: [BunTarget], - executes: () => bun("tgui:prettier"), -}); - -export const TguiSonarTarget = new Juke.Target({ - dependsOn: [BunTarget], - executes: () => bun("tgui:sonar"), + executes: () => bun('tgui:build'), }); export const TguiTscTarget = new Juke.Target({ dependsOn: [BunTarget], - executes: () => bun("tgui:tsc"), + executes: () => bun('tgui:tsc'), }); export const TguiTestTarget = new Juke.Target({ parameters: [CiParameter], dependsOn: [BunTarget], - executes: () => bun("tgui:test"), + executes: () => bun('tgui:test'), +}); + +export const BiomeCheckTarget = new Juke.Target({ + dependsOn: [BunTarget, BiomeInstallTarget], + executes: () => bunRoot('tgui:lint'), }); export const TguiLintTarget = new Juke.Target({ - dependsOn: [BunTarget, TguiPrettierTarget, TguiEslintTarget, TguiTscTarget], + dependsOn: [BunTarget, BiomeCheckTarget, TguiTscTarget], }); export const TguiDevTarget = new Juke.Target({ dependsOn: [BunTarget], - executes: ({ args }) => bun("tgui:dev", ...args), + executes: ({ args }) => bun('tgui:dev', ...args), }); export const TguiAnalyzeTarget = new Juke.Target({ dependsOn: [BunTarget], - executes: () => bun("tgui:analyze"), -}); - -export const TguiBenchTarget = new Juke.Target({ - dependsOn: [BunTarget], - executes: () => bun("tgui:bench"), -}); - -export const TguiPrettierFix = new Juke.Target({ - dependsOn: [BunTarget], - executes: () => bun("tgui:prettier-fix"), -}); - -export const TguiEslintFix = new Juke.Target({ - dependsOn: [BunTarget], - executes: () => bun("tgui:eslint-fix"), -}); - -export const TguiFix = new Juke.Target({ - dependsOn: [TguiPrettierFix, TguiEslintFix], + executes: () => bun('tgui:analyze'), }); export const TestTarget = new Juke.Target({ @@ -408,12 +390,12 @@ export const ServerTarget = new Juke.Target({ parameters: [DmVersionParameter, PortParameter], dependsOn: [BuildTarget], executes: async ({ get }) => { - const port = get(PortParameter) || "1337"; + const port = get(PortParameter) || '1337'; const options = { dmbFile: `${DME_NAME}.dmb`, namedDmVersion: get(DmVersionParameter), }; - await DreamDaemon(options, port, "-trusted -invisible"); + await DreamDaemon(options, port, '-trusted -invisible'); }, }); @@ -423,19 +405,19 @@ export const AllTarget = new Juke.Target({ export const TguiCleanTarget = new Juke.Target({ executes: async () => { - Juke.rm("tgui/public/.tmp", { recursive: true }); - Juke.rm("tgui/public/*.map"); - Juke.rm("tgui/public/*.{chunk,bundle,hot-update}.*"); - Juke.rm("tgui/packages/tgfont/dist", { recursive: true }); - Juke.rm("tgui/node_modules", { recursive: true }); + Juke.rm('tgui/public/.tmp', { recursive: true }); + Juke.rm('tgui/public/*.map'); + Juke.rm('tgui/public/*.{chunk,bundle,hot-update}.*'); + Juke.rm('tgui/packages/tgfont/dist', { recursive: true }); + Juke.rm('tgui/node_modules', { recursive: true }); }, }); export const CleanTarget = new Juke.Target({ dependsOn: [TguiCleanTarget], executes: async () => { - Juke.rm("*.{dmb,rsc}"); - Juke.rm("_maps/templates.dm"); + Juke.rm('*.{dmb,rsc}'); + Juke.rm('_maps/templates.dm'); }, }); @@ -445,24 +427,24 @@ export const CleanTarget = new Juke.Target({ export const CleanAllTarget = new Juke.Target({ dependsOn: [CleanTarget], executes: async () => { - Juke.logger.info("Cleaning up data/logs"); - Juke.rm("data/logs", { recursive: true }); + Juke.logger.info('Cleaning up data/logs'); + Juke.rm('data/logs', { recursive: true }); }, }); export const TgsTarget = new Juke.Target({ dependsOn: [TguiTarget], executes: async () => { - Juke.logger.info("Prepending TGS define"); - prependDefines("TGS"); + Juke.logger.info('Prepending TGS define'); + prependDefines('TGS'); }, }); Juke.setup({ file: import.meta.url }).then((code) => { // We're using the currently available quirk in Juke Build, which // prevents it from exiting on Windows, to wait on errors. - if (code !== 0 && process.argv.includes("--wait-on-error")) { - Juke.logger.error("Please inspect the error and close the window."); + if (code !== 0 && process.argv.includes('--wait-on-error')) { + Juke.logger.error('Please inspect the error and close the window.'); return; } diff --git a/tools/build/lib/bun.ts b/tools/build/lib/bun.ts index 0cb1a4e27e6..951af3f50fd 100644 --- a/tools/build/lib/bun.ts +++ b/tools/build/lib/bun.ts @@ -1,16 +1,28 @@ -import Juke from "../juke/index.js"; -import { mkdirSync } from "node:fs"; +import { mkdirSync } from 'node:fs'; +import Juke from '../juke/index.js'; let hasInstallFolder = false; export function bun(...args: any[]): Promise { if (!hasInstallFolder) { - mkdirSync("./tgui/node_modules/", { recursive: true }); + mkdirSync('./tgui/node_modules/', { recursive: true }); hasInstallFolder = true; } - return Juke.exec("bun", [...args.filter((arg) => typeof arg === "string")], { - cwd: "./tgui", + return Juke.exec('bun', [...args.filter((arg) => typeof arg === 'string')], { + cwd: './tgui', + shell: true, + }); +} + +export function bunRoot(...args: any[]): Promise { + if (!hasInstallFolder) { + mkdirSync('./node_modules/', { recursive: true }); + hasInstallFolder = true; + } + + return Juke.exec('bun', [...args.filter((arg) => typeof arg === 'string')], { + cwd: './', shell: true, }); } diff --git a/tools/dm-invalid-utf8-discovery/index.js b/tools/dm-invalid-utf8-discovery/index.js index c287e270cb5..ef2d3cecff5 100644 --- a/tools/dm-invalid-utf8-discovery/index.js +++ b/tools/dm-invalid-utf8-discovery/index.js @@ -7,7 +7,7 @@ let count = 0; while (queue.length) { let entries = await Promise.all( - queue.slice(0, 100).map((path) => readdir(path, { withFileTypes: true })) + queue.slice(0, 100).map((path) => readdir(path, { withFileTypes: true })), ); for (let i = 0; i < entries.length; ++i) { for (const entry of entries[i]) { diff --git a/tools/dm-invalid-utf8-discovery/package.json b/tools/dm-invalid-utf8-discovery/package.json index 55af8d18c86..ec37e671398 100644 --- a/tools/dm-invalid-utf8-discovery/package.json +++ b/tools/dm-invalid-utf8-discovery/package.json @@ -1,11 +1,11 @@ { - "name": "dm-invalid-utf8-discovery", - "version": "0.1.0", - "type":"module", - "dependencies": { - "utf-8-validate": "5.0.9" - }, - "contributors": [ - "spookerton (https://github.com/spookerton)" - ] + "name": "dm-invalid-utf8-discovery", + "version": "0.1.0", + "type": "module", + "dependencies": { + "utf-8-validate": "5.0.9" + }, + "contributors": [ + "spookerton (https://github.com/spookerton)" + ] } diff --git a/tools/hooks/README.md b/tools/hooks/README.md index c7105903972..1c34d538602 100644 --- a/tools/hooks/README.md +++ b/tools/hooks/README.md @@ -12,9 +12,9 @@ or other script you can run instead - see the links below for details. ## Hooks -* **Pre-commit**: Runs [mapmerge2] to reduce the diff on any changed maps. -* **DMI merger**: Attempts to [fix icon conflicts] when performing a Git merge. -* **DMM merger**: Attempts to [fix map conflicts] when performing a Git merge. +- **Pre-commit**: Runs [mapmerge2] to reduce the diff on any changed maps. +- **DMI merger**: Attempts to [fix icon conflicts] when performing a Git merge. +- **DMM merger**: Attempts to [fix map conflicts] when performing a Git merge. ## Adding New Hooks diff --git a/tools/icon_cutter/README.md b/tools/icon_cutter/README.md index 91edd1a4065..8bd416154aa 100644 --- a/tools/icon_cutter/README.md +++ b/tools/icon_cutter/README.md @@ -20,4 +20,4 @@ If they have been, the cutter will perform a full runthrough, and compile all in These dmis can then be committed, and badabing badaboom we have autocut sprites. -If you want to change the cutter version we have a set of config values in [dependancies.sh](../../dependencies.sh) that control it. +If you want to change the cutter version we have a set of config values in [dependancies.sh](../../dependencies.sh) that control it. diff --git a/tools/maplint/README.md b/tools/maplint/README.md index 82ee0bd0ced..47a21ae7210 100644 --- a/tools/maplint/README.md +++ b/tools/maplint/README.md @@ -1,4 +1,5 @@ # maplint + maplint is a tool that lets you prohibit anti-patterns in maps through simple rules. You can use maplint to do things like ban variable edits for specific types, ban specific variable edits, ban combinations of types, etc. ## Making lints @@ -6,6 +7,7 @@ maplint is a tool that lets you prohibit anti-patterns in maps through simple ru To create a lint, create a new file in the `lints` folder. Lints use [YAML](https://learnxinyminutes.com/docs/yaml/), which is very expressive, though can be a little complex. If you get stuck, read other lints in this folder. ### Typepaths + The root of the file is your typepaths. This will match not only that type, but also subtypes. For example: ```yml @@ -26,6 +28,7 @@ If you only want to match a specific typepath, prefix it with `=`. This: Alternatively, if you want to match ALL types, enter a single `*`, for wildcard. ### `banned` + The simplest rule is to completely ban a subtype. To do this, fill with `banned: true`. For example, this lint will ban `/mob/dog` and all subtypes: @@ -36,34 +39,35 @@ For example, this lint will ban `/mob/dog` and all subtypes: ``` ### `banned_neighbors` + If you want to ban other objects being on the same tile as another, you can specify `banned_neighbors`. -This takes a few forms. The simplest is just a list of types to not be next to. This lint will ban either cat_toy *or* cat_food (or their subtypes) from being on the same tile as a dog. +This takes a few forms. The simplest is just a list of types to not be next to. This lint will ban either cat*toy \_or* cat_food (or their subtypes) from being on the same tile as a dog. ```yml /mob/dog: banned_neighbors: - - /obj/item/cat_toy - - /obj/item/cat_food + - /obj/item/cat_toy + - /obj/item/cat_food ``` -This also supports the `=` format as specified before. This will ban `/mob/dog` being on the same tile as `/obj/item/toy` *only*. +This also supports the `=` format as specified before. This will ban `/mob/dog` being on the same tile as `/obj/item/toy` _only_. ```yml /mob/dog: banned_neighbors: - - =/obj/item/toy # Only the best toys for our dogs + - =/obj/item/toy # Only the best toys for our dogs ``` -Anything in this list will *not* include the object itself, meaning you can use it to make sure two of the same object are not on the same tile. For example, this lint will ban two dogs from being on the same tile: +Anything in this list will _not_ include the object itself, meaning you can use it to make sure two of the same object are not on the same tile. For example, this lint will ban two dogs from being on the same tile: ```yml /mob/dog: banned_neighbors: - - /mob/dog # We're a space station, not a dog park! + - /mob/dog # We're a space station, not a dog park! ``` -However, you can add a bit more specificity with `identical: true`. This will prohibit other instances of the *exact* same type *and* variable edits from being on the same tile. +However, you can add a bit more specificity with `identical: true`. This will prohibit other instances of the _exact_ same type _and_ variable edits from being on the same tile. ```yml /mob/dog: @@ -81,6 +85,7 @@ Finally, if you need maximum precision, you can specify a [regular expression](h ``` ### `banned_variables` + To ban all variable edits, you can specify `banned_variables: true` for a typepath. For instance, if we want to block dogs from getting any var-edits, we can write: ```yml @@ -119,10 +124,11 @@ Similar to [banned_neighbors](#banned_neighbors), you can specify a regular expr banned_variables: # Names must start with a capital letter name: - allow: { pattern: '^[A-Z].*$' } + allow: { pattern: "^[A-Z].*$" } ``` ### `help` + If you want a custom message to go with your lint, you can specify "help" in the root. ```yml diff --git a/tools/maplint/lints/cable_dir_varedits.yml b/tools/maplint/lints/cable_dir_varedits.yml index 366b82686c4..90a42d29691 100644 --- a/tools/maplint/lints/cable_dir_varedits.yml +++ b/tools/maplint/lints/cable_dir_varedits.yml @@ -1,5 +1,5 @@ /obj/structure/cable: banned_variables: - - dir - - d1 - - d2 + - dir + - d1 + - d2 diff --git a/tools/maplint/lints/merge_conflict_marker.yml b/tools/maplint/lints/merge_conflict_marker.yml index bdece05597e..04dbf08a677 100644 --- a/tools/maplint/lints/merge_conflict_marker.yml +++ b/tools/maplint/lints/merge_conflict_marker.yml @@ -1,5 +1,4 @@ -help: - This means you didn't clean up any potential merge conflicts, +help: This means you didn't clean up any potential merge conflicts, make sure everything in that area is correct. /obj/merge_conflict_marker: banned: true diff --git a/tools/maplint/lints/multiple_airlocks.yml b/tools/maplint/lints/multiple_airlocks.yml index 669272f61c0..345526bc4a1 100644 --- a/tools/maplint/lints/multiple_airlocks.yml +++ b/tools/maplint/lints/multiple_airlocks.yml @@ -1,3 +1,3 @@ /obj/machinery/door/airlock: banned_neighbors: - - /obj/machinery/door/airlock + - /obj/machinery/door/airlock diff --git a/tools/maplint/lints/multiple_area.yml b/tools/maplint/lints/multiple_area.yml index 91391cb2e96..c91572a3825 100644 --- a/tools/maplint/lints/multiple_area.yml +++ b/tools/maplint/lints/multiple_area.yml @@ -1,3 +1,3 @@ /area: banned_neighbors: - - /area + - /area diff --git a/tools/maplint/lints/multiple_beds.yml b/tools/maplint/lints/multiple_beds.yml index da96e679a3b..3cebf4b6e56 100644 --- a/tools/maplint/lints/multiple_beds.yml +++ b/tools/maplint/lints/multiple_beds.yml @@ -1,3 +1,3 @@ /obj/structure/bed: banned_neighbors: - - /obj/structure/bed + - /obj/structure/bed diff --git a/tools/maplint/lints/multiple_blood_effects.yml b/tools/maplint/lints/multiple_blood_effects.yml index 6ce90f31079..f513b5cf00e 100644 --- a/tools/maplint/lints/multiple_blood_effects.yml +++ b/tools/maplint/lints/multiple_blood_effects.yml @@ -1,3 +1,3 @@ =/obj/effect/decal/cleanable/blood: banned_neighbors: - - =/obj/effect/decal/cleanable/blood + - =/obj/effect/decal/cleanable/blood diff --git a/tools/maplint/lints/multiple_catwalks.yml b/tools/maplint/lints/multiple_catwalks.yml index 3b19e8d8129..6e2e3bf9357 100644 --- a/tools/maplint/lints/multiple_catwalks.yml +++ b/tools/maplint/lints/multiple_catwalks.yml @@ -1,3 +1,3 @@ /obj/structure/catwalk: banned_neighbors: - - /obj/structure/catwalk + - /obj/structure/catwalk diff --git a/tools/maplint/lints/multiple_dirt_effects.yml b/tools/maplint/lints/multiple_dirt_effects.yml index c8fb443e9ea..ef7d470f209 100644 --- a/tools/maplint/lints/multiple_dirt_effects.yml +++ b/tools/maplint/lints/multiple_dirt_effects.yml @@ -1,3 +1,3 @@ /obj/effect/decal/cleanable/dirt: banned_neighbors: - - /obj/effect/decal/cleanable/dirt + - /obj/effect/decal/cleanable/dirt diff --git a/tools/maplint/lints/multiple_firelocks.yml b/tools/maplint/lints/multiple_firelocks.yml index 5c751d8caef..79ff0728ae1 100644 --- a/tools/maplint/lints/multiple_firelocks.yml +++ b/tools/maplint/lints/multiple_firelocks.yml @@ -1,3 +1,3 @@ =/obj/machinery/door/firedoor: banned_neighbors: - - =/obj/machinery/door/firedoor + - =/obj/machinery/door/firedoor diff --git a/tools/maplint/lints/multiple_girders.yml b/tools/maplint/lints/multiple_girders.yml index 38a2a77871f..8367b04af0f 100644 --- a/tools/maplint/lints/multiple_girders.yml +++ b/tools/maplint/lints/multiple_girders.yml @@ -1,3 +1,3 @@ /obj/structure/girder: banned_neighbors: - - /obj/structure/girder + - /obj/structure/girder diff --git a/tools/maplint/lints/multiple_grilles.yml b/tools/maplint/lints/multiple_grilles.yml index c04829f4b7d..0fa21de8aab 100644 --- a/tools/maplint/lints/multiple_grilles.yml +++ b/tools/maplint/lints/multiple_grilles.yml @@ -1,3 +1,3 @@ /obj/structure/grille: banned_neighbors: - - /obj/structure/grille + - /obj/structure/grille diff --git a/tools/maplint/lints/multiple_lattice.yml b/tools/maplint/lints/multiple_lattice.yml index 3ad5253fbf2..8504fbc63f1 100644 --- a/tools/maplint/lints/multiple_lattice.yml +++ b/tools/maplint/lints/multiple_lattice.yml @@ -1,3 +1,3 @@ /obj/structure/lattice: banned_neighbors: - - /obj/structure/lattice + - /obj/structure/lattice diff --git a/tools/maplint/lints/multiple_tables.yml b/tools/maplint/lints/multiple_tables.yml index 0925fd843b0..d90b372baa6 100644 --- a/tools/maplint/lints/multiple_tables.yml +++ b/tools/maplint/lints/multiple_tables.yml @@ -1,3 +1,3 @@ /obj/structure/table: banned_neighbors: - - /obj/structure/table + - /obj/structure/table diff --git a/tools/maplint/lints/multiple_turf.yml b/tools/maplint/lints/multiple_turf.yml index 2a66f18398c..1ce790e9b82 100644 --- a/tools/maplint/lints/multiple_turf.yml +++ b/tools/maplint/lints/multiple_turf.yml @@ -1,3 +1,3 @@ /turf: banned_neighbors: - - /turf + - /turf diff --git a/tools/maplint/lints/pixel_varedits.yml b/tools/maplint/lints/pixel_varedits.yml index c496fa06da6..f572ba9e538 100644 --- a/tools/maplint/lints/pixel_varedits.yml +++ b/tools/maplint/lints/pixel_varedits.yml @@ -1,6 +1,6 @@ "*": banned_variables: - - pixel_w - - pixel_z - - step_x - - step_y + - pixel_w + - pixel_z + - step_x + - step_y diff --git a/tools/maplint/lints/stray_item.yml b/tools/maplint/lints/stray_item.yml index 0f5e6f4181a..4855b9a4bba 100644 --- a/tools/maplint/lints/stray_item.yml +++ b/tools/maplint/lints/stray_item.yml @@ -1,3 +1,3 @@ /turf/closed: banned_neighbors: - - =/obj/item + - =/obj/item diff --git a/tools/maplint/lints/wall_stacking.yml b/tools/maplint/lints/wall_stacking.yml index 42a21527d46..b9cd0a2e809 100644 --- a/tools/maplint/lints/wall_stacking.yml +++ b/tools/maplint/lints/wall_stacking.yml @@ -1,5 +1,5 @@ /turf/closed: banned_neighbors: - - /obj/machinery/door/airlock - - /obj/structure/lattice - - /obj/structure/window + - /obj/machinery/door/airlock + - /obj/structure/lattice + - /obj/structure/window diff --git a/tools/mapmerge2/readme.md b/tools/mapmerge2/readme.md index 71164bdb71f..0cd9f50e57e 100644 --- a/tools/mapmerge2/readme.md +++ b/tools/mapmerge2/readme.md @@ -16,8 +16,8 @@ To install the [Git hooks], open the `tools/hooks/` folder and double-click If using a Git GUI which is not compatible with the hooks: -* Before committing, double-click `Run Before Committing.bat` -* When a merge has map conflicts, double-click `Resolve Map Conflicts.bat` +- Before committing, double-click `Run Before Committing.bat` +- When a merge has map conflicts, double-click `Resolve Map Conflicts.bat` The console will show whether the operation succeeded. @@ -44,16 +44,16 @@ the map root is autodetected. Each script may either prompt for the desired map or be run with command-line parameters indicating which maps to act on. The scripts include: -* `convert.py` for converting maps to and from the TGM format. Used by +- `convert.py` for converting maps to and from the TGM format. Used by `tgm2dmm.bat` and `dmm2tgm.bat`. -* `mapmerge.py` for running the map merge on map backups saved by +- `mapmerge.py` for running the map merge on map backups saved by `Prepare Maps.bat`. Used by `mapmerge.bat` Implementation modules: -* `dmm.py` includes the map reader and writer. -* `mapmerge.py` includes the implementation of the map merge operation. -* `frontend.py` includes the common code for the frontend scripts. +- `dmm.py` includes the map reader and writer. +- `mapmerge.py` includes the implementation of the map merge operation. +- `frontend.py` includes the common code for the frontend scripts. `precommit.py` is run by the [Git hooks] if installed, and merges the new version of any map saved in the index (`git add`ed) with the old version stored diff --git a/tools/nano-tester/README.md b/tools/nano-tester/README.md index 8c01aa326bd..afc99699b2b 100644 --- a/tools/nano-tester/README.md +++ b/tools/nano-tester/README.md @@ -1,12 +1,15 @@ # NanoUI Template Tester + A simple utility for previewing how NanoUI templates will look out of game, useful for rapid development cycles. ## Setup + - Make sure you have Node.js ( https://nodejs.org/ ) installed. - Run `npm install` to install dependencies - Edit `index.js` to change the configuration to use the template you want to preview. - Edit `initialData.json` to contain the initial data that will be generated by your object's `ui_interact` proc. -- Run `node index.js` and then connect at http://localhost:8000/ +- Run `node index.js` and then connect at http://localhost:8000/ ## While Running + - You can update your template files, nano CSS or initialData.json at any time while the server is running. diff --git a/tools/nano-tester/index.html b/tools/nano-tester/index.html index f3cf4ba8550..ee6b24a9181 100644 --- a/tools/nano-tester/index.html +++ b/tools/nano-tester/index.html @@ -1,46 +1,53 @@ - + - - - - + + + + - - - - - - - - - - - - - - -

-
- - - \ No newline at end of file + + + + + + + + + + + + + + +
+ + + diff --git a/tools/nano-tester/index.js b/tools/nano-tester/index.js index 53eb6f35769..ecfd01ea68a 100644 --- a/tools/nano-tester/index.js +++ b/tools/nano-tester/index.js @@ -2,23 +2,23 @@ // // Mini webserver for testing NanoUI templates // -const fs = require('fs'); -const http = require('http'); -const mime = require('mime'); -const path = require('path'); -const url = require('url'); -const dot = require('dot'); +const fs = require("fs"); +const http = require("http"); +const mime = require("mime"); +const path = require("path"); +const url = require("url"); +const dot = require("dot"); // Configuration constants -var config = { - "port": 8000, // Port to listen on - "dir": "../../nano", // Path to SS13 nano folder +var config = { + port: 8000, // Port to listen on + dir: "../../nano", // Path to SS13 nano folder }; // Choose your templates here. Hint: You'll probably never change layout, main is the one you want. var templateData = { layout: "layout_default.tmpl", - main: "smes.tmpl" + main: "smes.tmpl", }; // In BYOND everything is sent to the client's byond cache, so its all in one flat directory. @@ -30,27 +30,28 @@ const extFolderMapping = { ".jpeg": path.join(process.cwd(), config.dir, "images"), ".gif": path.join(process.cwd(), config.dir, "images"), ".js": path.join(process.cwd(), config.dir, "js"), - ".css": path.join(process.cwd(), config.dir, "css"), - ".tmpl": path.join(process.cwd(), config.dir, "templates") + ".css": path.join(process.cwd(), config.dir, "css"), + ".tmpl": path.join(process.cwd(), config.dir, "templates"), }; // Read the shipped index.html as a doT template. -var genIndexHtml = dot.template(fs.readFileSync('index.html', 'utf8')); +var genIndexHtml = dot.template(fs.readFileSync("index.html", "utf8")); // the main thing -var server = http.createServer( function(request, response) { - - // extract the pathname from the request URL +var server = http.createServer(function (request, response) { + // extract the pathname from the request URL var pathname = url.parse(request.url).pathname; - + // Exception for front page - if (pathname === '/') { - let initialData = JSON.parse(fs.readFileSync('initialData.json', 'utf8')); - response.writeHead(200, {"Content-Type": "text/html"}); - response.write(genIndexHtml({ - initialDataJson: JSON.stringify(initialData), - templateDataJson: JSON.stringify(templateData) - })); + if (pathname === "/") { + let initialData = JSON.parse(fs.readFileSync("initialData.json", "utf8")); + response.writeHead(200, { "Content-Type": "text/html" }); + response.write( + genIndexHtml({ + initialDataJson: JSON.stringify(initialData), + templateDataJson: JSON.stringify(templateData), + }), + ); response.end(); return; } @@ -68,36 +69,37 @@ var server = http.createServer( function(request, response) { // console.log("Trying to serve ", pathname, " from ", filename); - // Does this path exist? - fs.exists(filename, function(gotPath) { - // no, bail out + // Does this path exist? + fs.exists(filename, function (gotPath) { + // no, bail out if (!gotPath) { console.warn("Path: %s File: %s NOT FOUND", pathname, filename); - response.writeHead(404, {"Content-Type": "text/plain"}); + response.writeHead(404, { "Content-Type": "text/plain" }); response.write("404 Not Found"); response.end(); return; } - // still here? filename is good + // still here? filename is good // look up the mime type by file extension - response.writeHead(200, {'Content-Type': mime.getType(filename)}); - + response.writeHead(200, { "Content-Type": mime.getType(filename) }); + // read and pass the file as a stream. Not really sure if this is better, // but it feels less block-ish than reading the whole file // and we get to do awesome things with listeners fs.createReadStream(filename, { - 'flags': 'r', - 'encoding': 'binary', - 'mode': 0x3146, // 0666 - 'bufferSize': 4 * 1024 - }).addListener( "data", function(chunk) { - response.write(chunk, 'binary'); - }).addListener( "close",function() { - response.end(); - }); - - }); + flags: "r", + encoding: "binary", + mode: 0x3146, // 0666 + bufferSize: 4 * 1024, + }) + .addListener("data", function (chunk) { + response.write(chunk, "binary"); + }) + .addListener("close", function () { + response.end(); + }); + }); }); // fire it up diff --git a/tools/nano-tester/package.json b/tools/nano-tester/package.json index f961d9ff870..b3e933ccba2 100644 --- a/tools/nano-tester/package.json +++ b/tools/nano-tester/package.json @@ -1,19 +1,19 @@ { - "name": "nano-tester", - "version": "1.0.0", - "description": "Test NanoUI Templates", - "main": "index.js", - "dependencies": { - "dot": "^1.1.2", - "mime": "^2.2.0" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "https://github.com/VOREStation/VOREStation.git" - }, - "author": "Leshana", - "license": "AGPL-3.0" + "name": "nano-tester", + "version": "1.0.0", + "description": "Test NanoUI Templates", + "main": "index.js", + "dependencies": { + "dot": "^1.1.2", + "mime": "^2.2.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/VOREStation/VOREStation.git" + }, + "author": "Leshana", + "license": "AGPL-3.0" } diff --git a/tools/playsound_finder/README.md b/tools/playsound_finder/README.md index 5e12e69f515..b566e73148b 100644 --- a/tools/playsound_finder/README.md +++ b/tools/playsound_finder/README.md @@ -1,4 +1,4 @@ This script extracts playsound() calls and their arguments and outputs it in a csv format In order to use this, open a shell at the root of the git directory and run `node tools/playsound_finder/index.js`. -It's pretty far from perfect, but hey, quicker than extracting playsound parameters by hand. \ No newline at end of file +It's pretty far from perfect, but hey, quicker than extracting playsound parameters by hand. diff --git a/tools/playsound_finder/index.js b/tools/playsound_finder/index.js index 020dda64468..df09677c1ea 100644 --- a/tools/playsound_finder/index.js +++ b/tools/playsound_finder/index.js @@ -1,14 +1,13 @@ -var fs = require('fs'); +var fs = require("fs"); // List all files in a directory in Node.js recursively in a synchronous fashion -var walkSync = function(dir, filelist) { +var walkSync = function (dir, filelist) { var files = fs.readdirSync(dir); filelist = filelist || []; - files.forEach(function(file) { + files.forEach(function (file) { if (fs.statSync(dir + file).isDirectory()) { - filelist = walkSync(dir + file + '/', filelist); - } - else { + filelist = walkSync(dir + file + "/", filelist); + } else { filelist.push(dir + file); } }); @@ -22,8 +21,8 @@ var findNearestAbsolute = (data, line) => { return str.trim().replace(/,/g, "|"); } } - return null -} + return null; +}; var main = () => { let files = walkSync("code/"); @@ -32,34 +31,41 @@ var main = () => { const data = fs.readFileSync(file, "utf8"); if (!data.match(/playsound.*/)) { - continue + continue; } - if(!matches[file]) matches[file] = []; + if (!matches[file]) matches[file] = []; const dataArray = data.split("\n"); let i = 1; for (let line of dataArray) { i++; - let m = line.match(/playsound.*/) + let m = line.match(/playsound.*/); if (m) { - matches[file].push({line: i, match: m[0], src: findNearestAbsolute(dataArray, i)}); + matches[file].push({ + line: i, + match: m[0], + src: findNearestAbsolute(dataArray, i), + }); } } } - Object.keys(matches).map(file => { + Object.keys(matches).map((file) => { let allResults = matches[file]; - allResults.map(obj => { + allResults.map((obj) => { obj.params = obj.match.split(","); for (var i = 0; i < obj.params.length; i++) { - obj.params[i] = obj.params[i].trim().replace(/playsound\(/g, "").replace(/\)/g, ""); + obj.params[i] = obj.params[i] + .trim() + .replace(/playsound\(/g, "") + .replace(/\)/g, ""); } - }) + }); }); // Final loop, spit out a csv - Object.keys(matches).map(file => { + Object.keys(matches).map((file) => { let thisFileCsvEntry = ""; let allResults = matches[file]; for (let matchObj of allResults) { @@ -67,6 +73,6 @@ var main = () => { } fs.appendFileSync("results.csv", thisFileCsvEntry); }); -} +}; -main(); \ No newline at end of file +main(); diff --git a/tools/playsound_finder/package.json b/tools/playsound_finder/package.json index b7e1961c37f..28cc71ea5cd 100644 --- a/tools/playsound_finder/package.json +++ b/tools/playsound_finder/package.json @@ -1,11 +1,11 @@ { - "name": "playsound_finder", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "Tigercat2000", - "license": "AGPL 3.0" + "name": "playsound_finder", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Tigercat2000", + "license": "AGPL 3.0" } diff --git a/tools/pull_request_hooks/autoChangelog.js b/tools/pull_request_hooks/autoChangelog.js index bc24481f182..2e9f656fe7e 100644 --- a/tools/pull_request_hooks/autoChangelog.js +++ b/tools/pull_request_hooks/autoChangelog.js @@ -1,42 +1,42 @@ import { parseChangelog } from "./changelogParser.js"; const safeYml = (string) => - string.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n"); + string.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n"); export function changelogToYml(changelog, login) { - const author = changelog.author || login; - const ymlLines = []; + const author = changelog.author || login; + const ymlLines = []; - ymlLines.push(`author: "${safeYml(author)}"`); - ymlLines.push(`delete-after: True`); - ymlLines.push(`changes:`); + ymlLines.push(`author: "${safeYml(author)}"`); + ymlLines.push(`delete-after: True`); + ymlLines.push(`changes:`); - for (const change of changelog.changes) { - ymlLines.push( - ` - ${change.type.changelogKey}: "${safeYml(change.description)}"` - ); - } + for (const change of changelog.changes) { + ymlLines.push( + ` - ${change.type.changelogKey}: "${safeYml(change.description)}"`, + ); + } - return ymlLines.join("\n"); + return ymlLines.join("\n"); } export async function processAutoChangelog({ github, context }) { - const changelog = parseChangelog(context.payload.pull_request.body); - if (!changelog || changelog.changes.length === 0) { - console.log("no changelog found"); - return; - } + const changelog = parseChangelog(context.payload.pull_request.body); + if (!changelog || changelog.changes.length === 0) { + console.log("no changelog found"); + return; + } - const yml = changelogToYml( - changelog, - context.payload.pull_request.user.login - ); + const yml = changelogToYml( + changelog, + context.payload.pull_request.user.login, + ); - github.rest.repos.createOrUpdateFileContents({ - owner: context.repo.owner, - repo: context.repo.repo, - path: `html/changelogs/AutoChangeLog-pr-${context.payload.pull_request.number}.yml`, - message: `Automatic changelog for PR #${context.payload.pull_request.number} [ci skip]`, - content: Buffer.from(yml).toString("base64"), - }); + github.rest.repos.createOrUpdateFileContents({ + owner: context.repo.owner, + repo: context.repo.repo, + path: `html/changelogs/AutoChangeLog-pr-${context.payload.pull_request.number}.yml`, + message: `Automatic changelog for PR #${context.payload.pull_request.number} [ci skip]`, + content: Buffer.from(yml).toString("base64"), + }); } diff --git a/tools/pull_request_hooks/autoChangelog.test.js b/tools/pull_request_hooks/autoChangelog.test.js index e7c29c384a9..821c29c6a42 100644 --- a/tools/pull_request_hooks/autoChangelog.test.js +++ b/tools/pull_request_hooks/autoChangelog.test.js @@ -3,19 +3,19 @@ import { changelogToYml } from "./autoChangelog.js"; import { parseChangelog } from "./changelogParser.js"; assert.equal( - changelogToYml( - parseChangelog(` + changelogToYml( + parseChangelog(` My cool PR! :cl: DenverCoder9 add: Adds new stuff add: Adds more stuff /:cl: - `) - ), + `), + ), - `author: "DenverCoder9" + `author: "DenverCoder9" delete-after: True changes: - rscadd: "Adds new stuff" - - rscadd: "Adds more stuff"` + - rscadd: "Adds more stuff"`, ); diff --git a/tools/pull_request_hooks/changelogConfig.js b/tools/pull_request_hooks/changelogConfig.js index 46b28f8d731..e460a2a3e64 100644 --- a/tools/pull_request_hooks/changelogConfig.js +++ b/tools/pull_request_hooks/changelogConfig.js @@ -8,106 +8,106 @@ * doesn't exist. */ export const CHANGELOG_ENTRIES = [ - [ - ["rscadd", "add", "adds"], - { - placeholders: [ - "Added new mechanics or gameplay changes", - "Added more things", - ], - }, - ], + [ + ["rscadd", "add", "adds"], + { + placeholders: [ + "Added new mechanics or gameplay changes", + "Added more things", + ], + }, + ], - [ - ["bugfix", "fix", "fixes"], - { - placeholders: ["fixed a few things"], - }, - ], + [ + ["bugfix", "fix", "fixes"], + { + placeholders: ["fixed a few things"], + }, + ], - [ - ["rscdel", "del", "dels"], - { - placeholders: ["Removed old things"], - }, - ], + [ + ["rscdel", "del", "dels"], + { + placeholders: ["Removed old things"], + }, + ], - [ - ["qol", "tweak"], - { - placeholders: ["made something easier to use"], - }, - ], + [ + ["qol", "tweak"], + { + placeholders: ["made something easier to use"], + }, + ], - [ - ["maptweak", "remap"], - { - placeholders: ["tweaked something in a map"], - }, - ], + [ + ["maptweak", "remap"], + { + placeholders: ["tweaked something in a map"], + }, + ], - [ - ["sound"], - { - placeholders: ["added/modified/removed audio or sound effects"], - }, - ], + [ + ["sound"], + { + placeholders: ["added/modified/removed audio or sound effects"], + }, + ], - [ - ["image"], - { - placeholders: ["added/modified/removed some icons or images"], - }, - ], + [ + ["image"], + { + placeholders: ["added/modified/removed some icons or images"], + }, + ], - [ - ["spellcheck", "typo"], - { - placeholders: ["fixed a few typos"], - }, - ], + [ + ["spellcheck", "typo"], + { + placeholders: ["fixed a few typos"], + }, + ], - [ - ["balance"], - { - placeholders: ["rebalanced something"], - }, - ], + [ + ["balance"], + { + placeholders: ["rebalanced something"], + }, + ], - [ - ["code_imp", "code"], - { - placeholders: ["changed some code"], - }, - ], + [ + ["code_imp", "code"], + { + placeholders: ["changed some code"], + }, + ], - [ - ["refactor"], - { - placeholders: ["refactored some code"], - }, - ], + [ + ["refactor"], + { + placeholders: ["refactored some code"], + }, + ], - [ - ["config"], - { - placeholders: ["changed some config setting"], - }, - ], + [ + ["config"], + { + placeholders: ["changed some config setting"], + }, + ], - [ - ["admin"], - { - placeholders: ["messed with admin stuff"], - }, - ], + [ + ["admin"], + { + placeholders: ["messed with admin stuff"], + }, + ], - [ - ["server"], - { - placeholders: ["something server ops should know"], - }, - ], + [ + ["server"], + { + placeholders: ["something server ops should know"], + }, + ], ]; // Valid changelog openers diff --git a/tools/pull_request_hooks/changelogParser.js b/tools/pull_request_hooks/changelogParser.js index ba572d24b40..f652d843573 100644 --- a/tools/pull_request_hooks/changelogParser.js +++ b/tools/pull_request_hooks/changelogParser.js @@ -4,80 +4,80 @@ const REGEX_CHANGELOG_LINE = /^(\w+): (.+)$/; const CHANGELOG_KEYS_TO_ENTRY = {}; for (const [types, entry] of changelogConfig.CHANGELOG_ENTRIES) { - const entryWithChangelogKey = { - ...entry, - changelogKey: types[0], - }; + const entryWithChangelogKey = { + ...entry, + changelogKey: types[0], + }; - for (const type of types) { - CHANGELOG_KEYS_TO_ENTRY[type] = entryWithChangelogKey; - } + for (const type of types) { + CHANGELOG_KEYS_TO_ENTRY[type] = entryWithChangelogKey; + } } function parseChangelogBody(lines, openTag) { - const [changelogOpening] = lines.splice(0, 1); + const [changelogOpening] = lines.splice(0, 1); - const author = - changelogOpening.substring(openTag.length).trim() || undefined; + const author = changelogOpening.substring(openTag.length).trim() || undefined; - const changelog = { - author, - changes: [], - }; + const changelog = { + author, + changes: [], + }; - for (const line of lines) { - if (line.trim().length === 0) { - continue; - } + for (const line of lines) { + if (line.trim().length === 0) { + continue; + } - for (const closeTag of changelogConfig.CHANGELOG_CLOSE_TAGS) { - if (line.startsWith(closeTag)) { - return changelog; - } - } + for (const closeTag of changelogConfig.CHANGELOG_CLOSE_TAGS) { + if (line.startsWith(closeTag)) { + return changelog; + } + } - const match = line.match(REGEX_CHANGELOG_LINE); - if (match) { - const [_, type, description] = match; + const match = line.match(REGEX_CHANGELOG_LINE); + if (match) { + const [_, type, description] = match; - const entry = CHANGELOG_KEYS_TO_ENTRY[type] || CHANGELOG_KEYS_TO_ENTRY["rscadd"]; + const entry = + CHANGELOG_KEYS_TO_ENTRY[type] || CHANGELOG_KEYS_TO_ENTRY["rscadd"]; - if (!entry || entry.placeholders.includes(description)) { - continue; - } + if (!entry || entry.placeholders.includes(description)) { + continue; + } - if (entry) { - changelog.changes.push({ - type: entry, - description, - }); - } - } else { - const lastChange = changelog.changes[changelog.changes.length - 1]; - if (lastChange) { - lastChange.description += `\n${line}`; - } - } - } + if (entry) { + changelog.changes.push({ + type: entry, + description, + }); + } + } else { + const lastChange = changelog.changes[changelog.changes.length - 1]; + if (lastChange) { + lastChange.description += `\n${line}`; + } + } + } - return changelog; + return changelog; } export function parseChangelog(text) { - if(text == null) { - return undefined; - } - const lines = text.split("\n").map((line) => line.trim()); + if (text == null) { + return undefined; + } + const lines = text.split("\n").map((line) => line.trim()); - for (let index = 0; index < lines.length; index++) { - const line = lines[index]; + for (let index = 0; index < lines.length; index++) { + const line = lines[index]; - for (const openTag of changelogConfig.CHANGELOG_OPEN_TAGS) { - if (line.startsWith(openTag)) { - return parseChangelogBody(lines.slice(index), openTag); - } - } - } + for (const openTag of changelogConfig.CHANGELOG_OPEN_TAGS) { + if (line.startsWith(openTag)) { + return parseChangelogBody(lines.slice(index), openTag); + } + } + } - return undefined; + return undefined; } diff --git a/tools/pull_request_hooks/changelogParser.test.js b/tools/pull_request_hooks/changelogParser.test.js index bcf044ee36d..aeea8664246 100644 --- a/tools/pull_request_hooks/changelogParser.test.js +++ b/tools/pull_request_hooks/changelogParser.test.js @@ -27,8 +27,8 @@ assert.equal(multiLineChangelog.author, undefined); assert.equal(multiLineChangelog.changes.length, 1); assert.equal(multiLineChangelog.changes[0].type.changelogKey, "rscadd"); assert.equal( - multiLineChangelog.changes[0].description, - "Adds new stuff\nto the game" + multiLineChangelog.changes[0].description, + "Adds new stuff\nto the game", ); // Placeholders diff --git a/tools/pull_request_hooks/removeGuideComments.js b/tools/pull_request_hooks/removeGuideComments.js index c7cdcd1ca67..6154cef6b65 100644 --- a/tools/pull_request_hooks/removeGuideComments.js +++ b/tools/pull_request_hooks/removeGuideComments.js @@ -19,14 +19,14 @@ export async function removeGuideComments({ github, context }) { let newBody = context.payload.pull_request.body; if (!newBody) { - console.log("PR body is empty, skipping..."); - return; + console.log("PR body is empty, skipping..."); + return; } for (const comment of comments) { newBody = newBody.replace( new RegExp(`^\\s*${escapeRegex(comment)}\\s*`, "gm"), - "\n" + "\n", ); } diff --git a/tools/pull_request_hooks/rerunFlakyTests.js b/tools/pull_request_hooks/rerunFlakyTests.js index 6625d9caa8c..f7a71396be8 100644 --- a/tools/pull_request_hooks/rerunFlakyTests.js +++ b/tools/pull_request_hooks/rerunFlakyTests.js @@ -3,222 +3,224 @@ const TITLE_BOT_HEADER = "title: "; // Only check jobs that start with these. // Helps make sure we don't restart something like screenshot tests or linters, which are not known to be flaky. -const CONSIDERED_JOBS = [ - "Integration Tests", -]; +const CONSIDERED_JOBS = ["Integration Tests"]; async function getFailedJobsForRun(github, context, workflowRunId, runAttempt) { - const { - data: { jobs }, - } = await github.rest.actions.listJobsForWorkflowRunAttempt({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: workflowRunId, - attempt_number: runAttempt, - }); + const { + data: { jobs }, + } = await github.rest.actions.listJobsForWorkflowRunAttempt({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: workflowRunId, + attempt_number: runAttempt, + }); - return jobs - .filter((job) => job.conclusion === "failure") - .filter((job) => - CONSIDERED_JOBS.some((title) => job.name.startsWith(title)) - ); + return jobs + .filter((job) => job.conclusion === "failure") + .filter((job) => + CONSIDERED_JOBS.some((title) => job.name.startsWith(title)), + ); } export async function rerunFlakyTests({ github, context }) { - const failingJobs = await getFailedJobsForRun( - github, - context, - context.payload.workflow_run.id, - context.payload.workflow_run.run_attempt - ); + const failingJobs = await getFailedJobsForRun( + github, + context, + context.payload.workflow_run.id, + context.payload.workflow_run.run_attempt, + ); - if (failingJobs.length > 1) { - console.log("Multiple jobs failing. PROBABLY not flaky, not rerunning."); - return; - } + if (failingJobs.length > 1) { + console.log("Multiple jobs failing. PROBABLY not flaky, not rerunning."); + return; + } - if (failingJobs.length === 0) { - throw new Error( - "rerunFlakyTests should not have run on a run with no failing jobs" - ); - } + if (failingJobs.length === 0) { + throw new Error( + "rerunFlakyTests should not have run on a run with no failing jobs", + ); + } - github.rest.actions.reRunWorkflowFailedJobs({ - owner: context.repo.owner, - repo: context.repo.repo, - run_id: context.payload.workflow_run.id, - }); + github.rest.actions.reRunWorkflowFailedJobs({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id, + }); } // Tries its best to extract a useful error title and message for the given log export function extractDetails(log) { - // Strip off timestamp - const lines = log.split(/^[0-9.:T\-]*?Z /gm); + // Strip off timestamp + const lines = log.split(/^[0-9.:T\-]*?Z /gm); - const failureRegex = /^\t?FAILURE #(?[0-9]+): (?.+)/; - const groupRegex = /^##\[group\](?.+)/; + const failureRegex = /^\t?FAILURE #(?[0-9]+): (?.+)/; + const groupRegex = /^##\[group\](?.+)/; - const failures = []; - let lastGroup = "root"; - let loggingFailure; + const failures = []; + let lastGroup = "root"; + let loggingFailure; - const newFailure = (failureMatch) => { - const { headline } = failureMatch.groups; + const newFailure = (failureMatch) => { + const { headline } = failureMatch.groups; - loggingFailure = { - headline, - group: lastGroup.replace("/datum/unit_test/", ""), - details: [], - }; - }; + loggingFailure = { + headline, + group: lastGroup.replace("/datum/unit_test/", ""), + details: [], + }; + }; - for (const line of lines) { - const groupMatch = line.match(groupRegex); - if (groupMatch) { - lastGroup = groupMatch.groups.group.trim(); - continue; - } + for (const line of lines) { + const groupMatch = line.match(groupRegex); + if (groupMatch) { + lastGroup = groupMatch.groups.group.trim(); + continue; + } - const failureMatch = line.match(failureRegex); + const failureMatch = line.match(failureRegex); - if (loggingFailure === undefined) { - if (!failureMatch) { - continue; - } + if (loggingFailure === undefined) { + if (!failureMatch) { + continue; + } - newFailure(failureMatch); - } else if (failureMatch || line.startsWith("##")) { - failures.push(loggingFailure); - loggingFailure = undefined; + newFailure(failureMatch); + } else if (failureMatch || line.startsWith("##")) { + failures.push(loggingFailure); + loggingFailure = undefined; - if (failureMatch) { - newFailure(failureMatch); - } - } else { - loggingFailure.details.push(line.trim()); - } - } + if (failureMatch) { + newFailure(failureMatch); + } + } else { + loggingFailure.details.push(line.trim()); + } + } - // We had no logged failures, there's not really anything we can do here - if (failures.length === 0) { - return { - title: "Flaky test failure with no obvious source", - failures, - }; - } + // We had no logged failures, there's not really anything we can do here + if (failures.length === 0) { + return { + title: "Flaky test failure with no obvious source", + failures, + }; + } - // We *could* create multiple failures for multiple groups. - // This would be important if we had multiple flaky tests at the same time. - // I'm choosing not to because it complicates this logic a bit, has the ability to go terribly wrong, - // and also because there's something funny to me about that increasing the urgency of fixing - // flaky tests. If it becomes a serious issue though, I would not mind this being fixed. - const uniqueGroups = new Set(failures.map((failure) => failure.group)); + // We *could* create multiple failures for multiple groups. + // This would be important if we had multiple flaky tests at the same time. + // I'm choosing not to because it complicates this logic a bit, has the ability to go terribly wrong, + // and also because there's something funny to me about that increasing the urgency of fixing + // flaky tests. If it becomes a serious issue though, I would not mind this being fixed. + const uniqueGroups = new Set(failures.map((failure) => failure.group)); - if (uniqueGroups.size > 1) { - return { - title: `Multiple flaky test failures in ${Array.from(uniqueGroups) - .sort() - .join(", ")}`, - failures, - }; - } + if (uniqueGroups.size > 1) { + return { + title: `Multiple flaky test failures in ${Array.from(uniqueGroups) + .sort() + .join(", ")}`, + failures, + }; + } - const failGroup = failures[0].group; + const failGroup = failures[0].group; - if (failures.length > 1) { - return { - title: `Multiple errors in flaky test ${failGroup}`, - failures, - }; - } + if (failures.length > 1) { + return { + title: `Multiple errors in flaky test ${failGroup}`, + failures, + }; + } - const failure = failures[0]; + const failure = failures[0]; - // Common patterns where we can always get a detailed title - const runtimeMatch = failure.headline.match(/Runtime in .+?: (?.+)/); - if (runtimeMatch) { - const runtime = runtimeMatch.groups.error.trim(); + // Common patterns where we can always get a detailed title + const runtimeMatch = failure.headline.match(/Runtime in .+?: (?.+)/); + if (runtimeMatch) { + const runtime = runtimeMatch.groups.error.trim(); - const invalidTimerMatch = runtime.match(/^Invalid timer:.+object:(?[^[]+).*delegate:(?.+?), source:/); - if (invalidTimerMatch) { - return { - title: `Flaky test ${failGroup}: Invalid timer: ${invalidTimerMatch.groups.proc.trim()} on ${invalidTimerMatch.groups.object.trim()}`, - failures, - }; - } + const invalidTimerMatch = runtime.match( + /^Invalid timer:.+object:(?[^[]+).*delegate:(?.+?), source:/, + ); + if (invalidTimerMatch) { + return { + title: `Flaky test ${failGroup}: Invalid timer: ${invalidTimerMatch.groups.proc.trim()} on ${invalidTimerMatch.groups.object.trim()}`, + failures, + }; + } - return { - title: `Flaky test ${failGroup}: ${runtime}`, - failures, - }; - } + return { + title: `Flaky test ${failGroup}: ${runtime}`, + failures, + }; + } - const hardDelMatch = failure.headline.match(/^(?\/[\w/]+) hard deleted .* times out of a total del count of/); - if (hardDelMatch) { - return { - title: `Flaky hard delete: ${hardDelMatch.groups.object}`, - failures, - }; - } + const hardDelMatch = failure.headline.match( + /^(?\/[\w/]+) hard deleted .* times out of a total del count of/, + ); + if (hardDelMatch) { + return { + title: `Flaky hard delete: ${hardDelMatch.groups.object}`, + failures, + }; + } - // Try to normalize the title and remove anything that might be variable - const normalizedError = failure.headline.replace(/\s*at .+?:[0-9]+.*/g, ""); // " at code.dm:123" + // Try to normalize the title and remove anything that might be variable + const normalizedError = failure.headline.replace(/\s*at .+?:[0-9]+.*/g, ""); // " at code.dm:123" - return { - title: `Flaky test ${failGroup}: ${normalizedError}`, - failures, - }; + return { + title: `Flaky test ${failGroup}: ${normalizedError}`, + failures, + }; } async function getExistingIssueId(graphql, context, title) { - // Hope you never have more than 100 of these open! - const { - repository: { - issues: { nodes: openFlakyTestIssues }, - }, - } = await graphql( - ` - query ($owner: String!, $repo: String!, $label: String!) { - repository(owner: $owner, name: $repo) { - issues( - labels: [$label] - first: 100 - orderBy: { field: CREATED_AT, direction: DESC } - states: [OPEN] - ) { - nodes { - number - title - body - } - } - } - } - `, - { - owner: context.repo.owner, - repo: context.repo.repo, - label: LABEL, - } - ); + // Hope you never have more than 100 of these open! + const { + repository: { + issues: { nodes: openFlakyTestIssues }, + }, + } = await graphql( + ` + query ($owner: String!, $repo: String!, $label: String!) { + repository(owner: $owner, name: $repo) { + issues( + labels: [$label] + first: 100 + orderBy: { field: CREATED_AT, direction: DESC } + states: [OPEN] + ) { + nodes { + number + title + body + } + } + } + } + `, + { + owner: context.repo.owner, + repo: context.repo.repo, + label: LABEL, + }, + ); - const exactTitle = openFlakyTestIssues.find((issue) => issue.title === title); - if (exactTitle !== undefined) { - return exactTitle.number; - } + const exactTitle = openFlakyTestIssues.find((issue) => issue.title === title); + if (exactTitle !== undefined) { + return exactTitle.number; + } - const foundInBody = openFlakyTestIssues.find((issue) => - issue.body.includes(``) - ); - if (foundInBody !== undefined) { - return foundInBody.number; - } + const foundInBody = openFlakyTestIssues.find((issue) => + issue.body.includes(``), + ); + if (foundInBody !== undefined) { + return foundInBody.number; + } - return undefined; + return undefined; } function createBody({ title, failures }, runUrl) { - return ` + return ` @@ -227,67 +229,67 @@ function createBody({ title, failures }, runUrl) { Failures: \`\`\` ${failures - .map( - (failure) => - `${failure.group}: ${failure.headline}\n\t${failure.details.join("\n")}` - ) - .join("\n")} + .map( + (failure) => + `${failure.group}: ${failure.headline}\n\t${failure.details.join("\n")}`, + ) + .join("\n")} \`\`\` `.replace(/^\s*/gm, ""); } export async function reportFlakyTests({ github, context }) { - const failedJobsFromLastRun = await getFailedJobsForRun( - github, - context, - context.payload.workflow_run.id, - context.payload.workflow_run.run_attempt - 1 - ); + const failedJobsFromLastRun = await getFailedJobsForRun( + github, + context, + context.payload.workflow_run.id, + context.payload.workflow_run.run_attempt - 1, + ); - // This could one day be relaxed if we face serious enough flaky test problems, so we're going to loop anyway - if (failedJobsFromLastRun.length !== 1) { - console.log( - "Multiple jobs failing after retry, assuming maintainer rerun." - ); + // This could one day be relaxed if we face serious enough flaky test problems, so we're going to loop anyway + if (failedJobsFromLastRun.length !== 1) { + console.log( + "Multiple jobs failing after retry, assuming maintainer rerun.", + ); - return; - } + return; + } - for (const job of failedJobsFromLastRun) { - const { data: log } = - await github.rest.actions.downloadJobLogsForWorkflowRun({ - owner: context.repo.owner, - repo: context.repo.repo, - job_id: job.id, - }); + for (const job of failedJobsFromLastRun) { + const { data: log } = + await github.rest.actions.downloadJobLogsForWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + job_id: job.id, + }); - const details = extractDetails(log); + const details = extractDetails(log); - const existingIssueId = await getExistingIssueId( - github.graphql, - context, - details.title - ); + const existingIssueId = await getExistingIssueId( + github.graphql, + context, + details.title, + ); - if (existingIssueId !== undefined) { - // Maybe in the future, if it's helpful, update the existing issue with new links - console.log(`Existing issue found: #${existingIssueId}`); - return; - } + if (existingIssueId !== undefined) { + // Maybe in the future, if it's helpful, update the existing issue with new links + console.log(`Existing issue found: #${existingIssueId}`); + return; + } - await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: details.title, - labels: [LABEL], - body: createBody( - details, - `https://github.com/${context.repo.owner}/${ - context.repo.repo - }/actions/runs/${context.payload.workflow_run.id}/attempts/${ - context.payload.workflow_run.run_attempt - 1 - }` - ), - }); - } + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: details.title, + labels: [LABEL], + body: createBody( + details, + `https://github.com/${context.repo.owner}/${ + context.repo.repo + }/actions/runs/${context.payload.workflow_run.id}/attempts/${ + context.payload.workflow_run.run_attempt - 1 + }`, + ), + }); + } } diff --git a/tools/pull_request_hooks/rerunFlakyTests.test.js b/tools/pull_request_hooks/rerunFlakyTests.test.js index 6a3300ff59b..7f0b2dfb015 100644 --- a/tools/pull_request_hooks/rerunFlakyTests.test.js +++ b/tools/pull_request_hooks/rerunFlakyTests.test.js @@ -3,43 +3,43 @@ import fs from "node:fs"; import { extractDetails } from "./rerunFlakyTests.js"; function extractDetailsFromPayload(filename) { - return extractDetails( - fs.readFileSync(`tests/flakyTestPayloads/${filename}.txt`, { - encoding: "utf8", - }) - ); + return extractDetails( + fs.readFileSync(`tests/flakyTestPayloads/${filename}.txt`, { + encoding: "utf8", + }), + ); } const chatClient = extractDetailsFromPayload("chat_client"); assert.equal( - chatClient.title, - "Flaky hard delete: /datum/computer_file/program/chatclient" + chatClient.title, + "Flaky hard delete: /datum/computer_file/program/chatclient", ); assert.equal(chatClient.failures.length, 1); const monkeyBusiness = extractDetailsFromPayload("monkey_business"); assert.equal( - monkeyBusiness.title, - "Flaky test monkey_business: Cannot execute null.resolve()." + monkeyBusiness.title, + "Flaky test monkey_business: Cannot execute null.resolve().", ); assert.equal(monkeyBusiness.failures.length, 1); const shapeshift = extractDetailsFromPayload("shapeshift"); assert.equal( - shapeshift.title, - "Multiple errors in flaky test shapeshift_spell" + shapeshift.title, + "Multiple errors in flaky test shapeshift_spell", ); assert.equal(shapeshift.failures.length, 16); const multipleFailures = extractDetailsFromPayload("multiple_failures"); assert.equal( - multipleFailures.title, - "Multiple flaky test failures in more_shapeshift_spell, shapeshift_spell" + multipleFailures.title, + "Multiple flaky test failures in more_shapeshift_spell, shapeshift_spell", ); assert.equal(multipleFailures.failures.length, 2); const invalidTimer = extractDetailsFromPayload("invalid_timer"); assert.equal( - invalidTimer.title, - "Flaky test monkey_business: Invalid timer: /datum/looping_sound/proc/start_sound_loop() on /datum/looping_sound/showering" + invalidTimer.title, + "Flaky test monkey_business: Invalid timer: /datum/looping_sound/proc/start_sound_loop() on /datum/looping_sound/showering", ); diff --git a/tools/registration/config.json.example b/tools/registration/config.json.example index a95663c9230..88a0a4a3fe4 100644 --- a/tools/registration/config.json.example +++ b/tools/registration/config.json.example @@ -1,6 +1,6 @@ { - "port": 6969, - "token": "your-token-goes-here", - "guildId": "your-guild-snowflake-goes-here", - "roleId": "your-role-snowflake-goes-here" + "port": 6969, + "token": "your-token-goes-here", + "guildId": "your-guild-snowflake-goes-here", + "roleId": "your-role-snowflake-goes-here" } diff --git a/tools/registration/index.js b/tools/registration/index.js index af354882824..99be9650b1f 100644 --- a/tools/registration/index.js +++ b/tools/registration/index.js @@ -3,70 +3,74 @@ const { Client, GatewayIntentBits } = require("discord.js"); const { port, token, guildId, roleId } = require("./config.json"); async function main() { - const client = new Client({ intents: [] }); - await client.login(token); + const client = new Client({ intents: [] }); + await client.login(token); - const guild = await client.guilds.fetch(guildId); - if (!guild) { - console.error("ERROR in config, unable to resolve guild " + guildId); - return; - } + const guild = await client.guilds.fetch(guildId); + if (!guild) { + console.error("ERROR in config, unable to resolve guild " + guildId); + return; + } - const role = await guild.roles.fetch(roleId); - if (!role) { - console.error("ERROR in config, invalid role ID ", roleId); - return; - } + const role = await guild.roles.fetch(roleId); + if (!role) { + console.error("ERROR in config, invalid role ID ", roleId); + return; + } - const server = http.createServer({}, (req, res) => { - const url = req.url; - if (!url) { - res.writeHead(400, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify({ data: "error parsing URL" })) - return; - } + const server = http.createServer({}, (req, res) => { + const url = req.url; + if (!url) { + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ data: "error parsing URL" })); + return; + } - let urlObj; - try { - urlObj = new URL(`http://localhost${url}`); - } catch (err) { - res.writeHead(400, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify({ data: "error parsing URL: " + err })) - return; - } - if (!urlObj.search) { - res.writeHead(400, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify({ data: "error parsing URL" })) - return; - } + let urlObj; + try { + urlObj = new URL(`http://localhost${url}`); + } catch (err) { + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ data: "error parsing URL: " + err })); + return; + } + if (!urlObj.search) { + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ data: "error parsing URL" })); + return; + } - const params = urlObj.searchParams; - const member_id = params.get("member"); + const params = urlObj.searchParams; + const member_id = params.get("member"); - if (!member_id) { - res.writeHead(400, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify({ data: "error parsing URL" })) - return; - } + if (!member_id) { + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ data: "error parsing URL" })); + return; + } - let memberIdRaw; - try { - memberIdRaw = JSON.parse(member_id); - } catch(err) { - res.writeHead(400, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify({ data: "error parsing URL: " + err })) - return; - } + let memberIdRaw; + try { + memberIdRaw = JSON.parse(member_id); + } catch (err) { + res.writeHead(400, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ data: "error parsing URL: " + err })); + return; + } - guild.members.addRole({ user: memberIdRaw, role, reason: "SS13 Registration" }) - console.log("Successfully registered ", memberIdRaw); + guild.members.addRole({ + user: memberIdRaw, + role, + reason: "SS13 Registration", + }); + console.log("Successfully registered ", memberIdRaw); - res.writeHead(200, { 'Content-Type': 'application/json' }); - res.end(JSON.stringify({ data: "success" })) - }); + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ data: "success" })); + }); - server.listen(port); - console.log("Server running on port", port); + server.listen(port); + console.log("Server running on port", port); } main(); diff --git a/tools/registration/package.json b/tools/registration/package.json index e2b1bd7fe19..5b133c2f283 100644 --- a/tools/registration/package.json +++ b/tools/registration/package.json @@ -1,14 +1,14 @@ { - "name": "registration", - "version": "1.0.0", - "description": "Small discord.js bot to handle adding member roles on discord registration", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "tigercat2000", - "license": "MIT", - "dependencies": { - "discord.js": "^14.21.0" - } + "name": "registration", + "version": "1.0.0", + "description": "Small discord.js bot to handle adding member roles on discord registration", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "tigercat2000", + "license": "MIT", + "dependencies": { + "discord.js": "^14.21.0" + } } diff --git a/verdigris/README.md b/verdigris/README.md index 202dc340014..e5ef6da9855 100644 --- a/verdigris/README.md +++ b/verdigris/README.md @@ -1,5 +1,7 @@ # Verdigris + ## An in-tree rust module for [VOREStation](https://github.com/VOREStation/VOREStation) Currently implemented: - - Random map cellular automata + +- Random map cellular automata diff --git a/vorestation.dme b/vorestation.dme index 4e164d4e6b1..344e95c2d07 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -3428,6 +3428,7 @@ #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\passive.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\penguin.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\passive\possum.dm" +#include "code\modules\mob\living\simple_mob\subtypes\animal\passive\raccoon.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\pets\bird.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\pets\bird_vr.dm" #include "code\modules\mob\living\simple_mob\subtypes\animal\pets\cat.dm"